Modelo

source("../../lib/som-utils.R")

Attaching package: 'dplyr'
The following objects are masked from 'package:stats':

    filter, lag
The following objects are masked from 'package:base':

    intersect, setdiff, setequal, union
source("../../lib/maps-utils.R")
Linking to GEOS 3.8.0, GDAL 3.0.4, PROJ 6.3.1

Carga del modelo desde disco

mpr.set_base_path_analysis()
model <- mpr.load_model("som-353.rds.xz")
summary(model)
SOM of size 5x5 with a hexagonal topology and a bubble neighbourhood function.
The number of data layers is 1.
Distance measure(s) used: sumofsquares.
Training data included: 94881 objects.
Mean distance to the closest unit in the map: 0.375.
plot(model, type="changes")

Carga del dataset de entrada

df <- mpr.load_data("datos_mes.csv.xz")
df
summary(df)
 id_estacion           fecha             fecha_cnt           tmax      
 Length:94881       Length:94881       Min.   : 1.000   Min.   :-53.0  
 Class :character   Class :character   1st Qu.: 4.000   1st Qu.:148.0  
 Mode  :character   Mode  :character   Median : 6.000   Median :198.0  
                                       Mean   : 6.497   Mean   :200.2  
                                       3rd Qu.: 9.000   3rd Qu.:255.0  
                                       Max.   :12.000   Max.   :403.0  
      tmin             precip           nevada           prof_nieve      
 Min.   :-121.00   Min.   :  0.00   Min.   :0.000000   Min.   :   0.000  
 1st Qu.:  53.00   1st Qu.:  3.00   1st Qu.:0.000000   1st Qu.:   0.000  
 Median :  98.00   Median : 10.00   Median :0.000000   Median :   0.000  
 Mean   :  98.86   Mean   : 16.25   Mean   :0.000295   Mean   :   0.467  
 3rd Qu.: 148.00   3rd Qu.: 22.00   3rd Qu.:0.000000   3rd Qu.:   0.000  
 Max.   : 254.00   Max.   :422.00   Max.   :6.000000   Max.   :1834.000  
    longitud        latitud            altitud      
 Min.   :27.82   Min.   :-17.8889   Min.   :   1.0  
 1st Qu.:38.28   1st Qu.: -5.6417   1st Qu.:  42.0  
 Median :40.82   Median : -3.4500   Median : 247.0  
 Mean   :39.66   Mean   : -3.4350   Mean   : 418.5  
 3rd Qu.:42.08   3rd Qu.:  0.4914   3rd Qu.: 656.0  
 Max.   :43.57   Max.   :  4.2156   Max.   :2535.0  

Carga de los mapas

world <- ne_countries(scale = "medium", returnclass = "sf")
spain <- subset(world, admin == "Spain")

Mapa de densidad

plot(model, type="count", shape = "straight", palette.name = mpr.degrade.bleu)

NĂºmero de elementos en cada celda:

nb <- table(model$unit.classif)
print(nb)

   1    2    3    4    5    6    7    8    9   10   11   12   13   14   15   16 
  97 1443 2930 4595 5955   21  908 2321 6843 7072  847 4558 6817 7316 7017    2 
  17   18   19   20   21   22   23   24   25 
  73    7 4165 7305    5 5757    3 8979 9845 

ComprobaciĂ³n de nodos vacĂ­os:

dim_model <- 5*5;
len_nb = length(nb);
empty_nodes <- dim_model != len_nb;
if (empty_nodes) {
  print(paste("[Warning] Existen nodos vacĂ­os: ", len_nb, "/", dim_model))
}

Mapa de distancia entre vecinos

plot(model, type="dist.neighbours", shape = "straight")

Influencia de las variables

model_colnames = c("tmax", "tmin", "precip", "nevada", "prof_nieve")
model_ncol = length(model_colnames)

Mapa de variables.

plot(model, shape = "straight")

Mapa de calor por variable

par(mfrow=c(3,4))
for (j in 1:model_ncol) {
  plot(model, type="property", property=getCodes(model,1)[,j],
    palette.name=mpr.coolBlueHotRed,
    main=model_colnames[j],
    cex=0.5, shape = "straight")
}

CorrelaciĂ³n para cada columna del vector de nodos

if (!empty_nodes) {
  cor <- apply(getCodes(model,1), 2, mpr.weighted.correlation, w=nb, som=model)
  print(cor)
}
           tmax       tmin     precip       nevada   prof_nieve
[1,]  0.6687724  0.5712344 -0.6933684 -0.018686276 -0.075945449
[2,] -0.6236142 -0.6549769 -0.3375124  0.006815374  0.007225463

RepresentaciĂ³n de cada variable en un mapa de factores:

if (!empty_nodes) {
  par(mfrow=c(1,1))
  plot(cor[1,], cor[2,], xlim=c(-1,1), ylim=c(-1,1), type="n")
  lines(c(-1,1),c(0,0))
  lines(c(0,0),c(-1,1))
  text(cor[1,], cor[2,], labels=model_colnames, cex=0.75)
  symbols(0,0,circles=1,inches=F,add=T)
}

Importancia de cada variable - varianza ponderada por el tamaño de la celda:

if (!empty_nodes) {
  sigma2 <- sqrt(apply(getCodes(model,1),2,function(x,effectif)
     {m<-sum(effectif*(x-weighted.mean(x,effectif))^2)/(sum(effectif)-1)},
     effectif=nb))
  print(sort(sigma2,decreasing=T))
}
    nevada prof_nieve       tmax       tmin     precip 
 0.9750486  0.9650419  0.9629507  0.9606522  0.9509582 

Clustering

if (!empty_nodes) {
  hac <- mpr.hac(model, nb)
}

VisualizaciĂ³n de 3 clĂºsteres:

if (!empty_nodes) {
  plot(hac, hang=-1, labels=F)
  rect.hclust(hac, k=3)
}

VisualizaciĂ³n de los clĂºsters en el mapa

A quĂ© clĂºster pertenece cada nodo del mapa de kohonen:

if (!empty_nodes) {
  groups <- cutree(hac, k=3)
  plot(model, type="mapping",
    bgcol=c("steelblue1","sienna1","yellowgreen","red","blue","yellow","purple","green","white","#1f77b4", '#ff7f0e', '#2ca02c', '#d62728', '#9467bd', '#8c564b', '#e377c2')[groups],
    shape = "straight", labels = "")
  add.cluster.boundaries(model, clustering=groups)
}

AnĂ¡lisis de las observaciones de cada cluster

if (!empty_nodes) {
  # Asignamos a cada registro su clĂºster
  df$cluster <- groups[model$unit.classif]
}

Nuevos dataframes por cluster

if (!empty_nodes) {
  # Creo nuevos dataframes, uno por cada clĂºster.
  df.cluster01 <- subset(df, cluster==1)
  df.cluster02 <- subset(df, cluster==2)
  df.cluster03 <- subset(df, cluster==3)

  # Extraigo del dataframe las features.
  df.cluster01 <- select(df.cluster01, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster02 <- select(df.cluster02, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster03 <- select(df.cluster03, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
}
if (!empty_nodes) summary(df.cluster01)
   fecha_cnt           tmax            tmin             precip      
 Min.   : 1.000   Min.   :-53.0   Min.   :-121.00   Min.   :  0.00  
 1st Qu.: 4.000   1st Qu.:148.0   1st Qu.:  53.00   1st Qu.:  3.00  
 Median : 6.000   Median :198.0   Median :  98.00   Median : 10.00  
 Mean   : 6.497   Mean   :200.2   Mean   :  98.87   Mean   : 16.25  
 3rd Qu.: 9.000   3rd Qu.:255.0   3rd Qu.: 148.00   3rd Qu.: 22.00  
 Max.   :12.000   Max.   :403.0   Max.   : 254.00   Max.   :422.00  
     nevada            prof_nieve          longitud        latitud        
 Min.   :0.0000000   Min.   :  0.0000   Min.   :27.82   Min.   :-17.8889  
 1st Qu.:0.0000000   1st Qu.:  0.0000   1st Qu.:38.28   1st Qu.: -5.6417  
 Median :0.0000000   Median :  0.0000   Median :40.82   Median : -3.4500  
 Mean   :0.0001897   Mean   :  0.3974   Mean   :39.66   Mean   : -3.4350  
 3rd Qu.:0.0000000   3rd Qu.:  0.0000   3rd Qu.:42.08   3rd Qu.:  0.4914  
 Max.   :3.0000000   Max.   :892.0000   Max.   :43.57   Max.   :  4.2156  
    altitud      
 Min.   :   1.0  
 1st Qu.:  42.0  
 Median : 247.0  
 Mean   : 418.5  
 3rd Qu.: 656.0  
 Max.   :2535.0  
if (!empty_nodes) summary(df.cluster02)
   fecha_cnt      tmax            tmin        precip          nevada   
 Min.   :2   Min.   :71.00   Min.   :-1   Min.   :14.00   Min.   :4.0  
 1st Qu.:2   1st Qu.:72.25   1st Qu.:-1   1st Qu.:15.25   1st Qu.:4.5  
 Median :2   Median :73.50   Median :-1   Median :16.50   Median :5.0  
 Mean   :2   Mean   :73.50   Mean   :-1   Mean   :16.50   Mean   :5.0  
 3rd Qu.:2   3rd Qu.:74.75   3rd Qu.:-1   3rd Qu.:17.75   3rd Qu.:5.5  
 Max.   :2   Max.   :76.00   Max.   :-1   Max.   :19.00   Max.   :6.0  
   prof_nieve    longitud        latitud          altitud     
 Min.   : 5   Min.   :40.48   Min.   :-3.450   Min.   :263.0  
 1st Qu.: 7   1st Qu.:40.78   1st Qu.:-2.846   1st Qu.:349.3  
 Median : 9   Median :41.08   Median :-2.242   Median :435.6  
 Mean   : 9   Mean   :41.08   Mean   :-2.242   Mean   :435.6  
 3rd Qu.:11   3rd Qu.:41.37   3rd Qu.:-1.637   3rd Qu.:521.8  
 Max.   :13   Max.   :41.67   Max.   :-1.033   Max.   :608.1  
if (!empty_nodes) summary(df.cluster03)
   fecha_cnt        tmax           tmin           precip         nevada 
 Min.   :2.0   Min.   :-4.0   Min.   :-51.0   Min.   :19.0   Min.   :0  
 1st Qu.:2.0   1st Qu.: 0.0   1st Qu.:-48.0   1st Qu.:33.0   1st Qu.:0  
 Median :3.0   Median :35.0   Median :-26.0   Median :49.0   Median :0  
 Mean   :2.6   Mean   :20.6   Mean   :-32.8   Mean   :41.4   Mean   :0  
 3rd Qu.:3.0   3rd Qu.:36.0   3rd Qu.:-23.0   3rd Qu.:50.0   3rd Qu.:0  
 Max.   :3.0   Max.   :36.0   Max.   :-16.0   Max.   :56.0   Max.   :0  
   prof_nieve      longitud        latitud         altitud    
 Min.   :1017   Min.   :40.78   Min.   :-4.01   Min.   :1894  
 1st Qu.:1073   1st Qu.:40.78   1st Qu.:-4.01   1st Qu.:1894  
 Median :1168   Median :40.78   Median :-4.01   Median :1894  
 Mean   :1317   Mean   :40.78   Mean   :-4.01   Mean   :1894  
 3rd Qu.:1494   3rd Qu.:40.78   3rd Qu.:-4.01   3rd Qu.:1894  
 Max.   :1834   Max.   :40.78   Max.   :-4.01   Max.   :1894  

NĂºmero de elementos en cada clĂºster

if (!empty_nodes) {
  df.clusters.dim <- c(dim(df.cluster01)[1], dim(df.cluster02)[1], dim(df.cluster03)[1])
  barplot(df.clusters.dim,
          names.arg = c("cluster01", "cluster02", "cluster03"),
          col = "steelblue1")
}

DistribuciĂ³n de los datos

if (!empty_nodes) mpr.hist(df.cluster01)

if (!empty_nodes) mpr.hist(df.cluster02)

if (!empty_nodes) mpr.hist(df.cluster03)

if (!empty_nodes) mpr.boxplot(df.cluster01)
if (!empty_nodes) mpr.boxplot(df.cluster02)

if (!empty_nodes) mpr.boxplot(df.cluster03)

LocalizaciĂ³n geogrĂ¡fica de las estaciones de medida de cada cluster

# Agrupa por longitud y latitud para rellenar el mapa con menos datos.
if (!empty_nodes) {
  df.cluster01.grouped <- mpr.group_by_geo(df.cluster01)
  df.cluster02.grouped <- mpr.group_by_geo(df.cluster02)
  df.cluster03.grouped <- mpr.group_by_geo(df.cluster03)
}
if (!empty_nodes) mpr.draw_map(spain, df.cluster01.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster02.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster03.grouped)

VisualizaciĂ³n de 4 clĂºsteres:

if (!empty_nodes) {
  plot(hac, hang=-1, labels=F)
  rect.hclust(hac, k=4)
}

VisualizaciĂ³n de los clĂºsters en el mapa

A quĂ© clĂºster pertenece cada nodo del mapa de kohonen:

if (!empty_nodes) {
  groups <- cutree(hac, k=4)
  plot(model, type="mapping",
    bgcol=c("steelblue1","sienna1","yellowgreen","red","blue","yellow","purple","green","white","#1f77b4", '#ff7f0e', '#2ca02c', '#d62728', '#9467bd', '#8c564b', '#e377c2')[groups],
    shape = "straight", labels = "")
  add.cluster.boundaries(model, clustering=groups)
}

AnĂ¡lisis de las observaciones de cada cluster

if (!empty_nodes) {
  # Asignamos a cada registro su clĂºster
  df$cluster <- groups[model$unit.classif]
}

Nuevos dataframes por cluster

if (!empty_nodes) {
  # Creo nuevos dataframes, uno por cada clĂºster.
  df.cluster01 <- subset(df, cluster==1)
  df.cluster02 <- subset(df, cluster==2)
  df.cluster03 <- subset(df, cluster==3)
  df.cluster04 <- subset(df, cluster==4)

  # Extraigo del dataframe las features.
  df.cluster01 <- select(df.cluster01, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster02 <- select(df.cluster02, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster03 <- select(df.cluster03, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster04 <- select(df.cluster04, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
}
if (!empty_nodes) summary(df.cluster01)
   fecha_cnt           tmax            tmin             precip      
 Min.   : 1.000   Min.   :-53.0   Min.   :-121.00   Min.   :  0.00  
 1st Qu.: 4.000   1st Qu.:148.0   1st Qu.:  53.00   1st Qu.:  3.00  
 Median : 6.000   Median :198.0   Median :  98.00   Median : 10.00  
 Mean   : 6.497   Mean   :200.2   Mean   :  98.87   Mean   : 16.25  
 3rd Qu.: 9.000   3rd Qu.:255.0   3rd Qu.: 148.00   3rd Qu.: 22.00  
 Max.   :12.000   Max.   :403.0   Max.   : 254.00   Max.   :422.00  
     nevada           prof_nieve          longitud        latitud        
 Min.   :0.00e+00   Min.   :  0.0000   Min.   :27.82   Min.   :-17.8889  
 1st Qu.:0.00e+00   1st Qu.:  0.0000   1st Qu.:38.28   1st Qu.: -5.6417  
 Median :0.00e+00   Median :  0.0000   Median :40.82   Median : -3.4500  
 Mean   :3.16e-05   Mean   :  0.3973   Mean   :39.66   Mean   : -3.4351  
 3rd Qu.:0.00e+00   3rd Qu.:  0.0000   3rd Qu.:42.08   3rd Qu.:  0.4914  
 Max.   :1.00e+00   Max.   :892.0000   Max.   :43.57   Max.   :  4.2156  
    altitud      
 Min.   :   1.0  
 1st Qu.:  42.0  
 Median : 247.0  
 Mean   : 418.5  
 3rd Qu.: 656.0  
 Max.   :2535.0  
if (!empty_nodes) summary(df.cluster02)
   fecha_cnt      tmax            tmin        precip          nevada   
 Min.   :2   Min.   :71.00   Min.   :-1   Min.   :14.00   Min.   :4.0  
 1st Qu.:2   1st Qu.:72.25   1st Qu.:-1   1st Qu.:15.25   1st Qu.:4.5  
 Median :2   Median :73.50   Median :-1   Median :16.50   Median :5.0  
 Mean   :2   Mean   :73.50   Mean   :-1   Mean   :16.50   Mean   :5.0  
 3rd Qu.:2   3rd Qu.:74.75   3rd Qu.:-1   3rd Qu.:17.75   3rd Qu.:5.5  
 Max.   :2   Max.   :76.00   Max.   :-1   Max.   :19.00   Max.   :6.0  
   prof_nieve    longitud        latitud          altitud     
 Min.   : 5   Min.   :40.48   Min.   :-3.450   Min.   :263.0  
 1st Qu.: 7   1st Qu.:40.78   1st Qu.:-2.846   1st Qu.:349.3  
 Median : 9   Median :41.08   Median :-2.242   Median :435.6  
 Mean   : 9   Mean   :41.08   Mean   :-2.242   Mean   :435.6  
 3rd Qu.:11   3rd Qu.:41.37   3rd Qu.:-1.637   3rd Qu.:521.8  
 Max.   :13   Max.   :41.67   Max.   :-1.033   Max.   :608.1  
if (!empty_nodes) summary(df.cluster03)
   fecha_cnt           tmax            tmin            precip     
 Min.   : 1.000   Min.   : 69.0   Min.   :-15.00   Min.   : 3.00  
 1st Qu.: 2.000   1st Qu.: 89.0   1st Qu.: -5.00   1st Qu.: 7.50  
 Median : 2.000   Median : 96.0   Median : 27.00   Median :12.00  
 Mean   : 6.143   Mean   :100.4   Mean   : 14.29   Mean   :11.86  
 3rd Qu.:12.000   3rd Qu.:110.0   3rd Qu.: 31.50   3rd Qu.:14.50  
 Max.   :12.000   Max.   :140.0   Max.   : 35.00   Max.   :24.00  
     nevada        prof_nieve       longitud        latitud      
 Min.   :2.000   Min.   :0.000   Min.   :40.48   Min.   :-3.450  
 1st Qu.:2.000   1st Qu.:0.000   1st Qu.:40.48   1st Qu.:-3.450  
 Median :2.000   Median :1.000   Median :41.67   Median :-1.033  
 Mean   :2.143   Mean   :1.429   Mean   :41.16   Mean   :-2.069  
 3rd Qu.:2.000   3rd Qu.:1.000   3rd Qu.:41.67   3rd Qu.:-1.033  
 Max.   :3.000   Max.   :7.000   Max.   :41.67   Max.   :-1.033  
    altitud     
 Min.   :263.0  
 1st Qu.:263.0  
 Median :263.0  
 Mean   :410.9  
 3rd Qu.:608.1  
 Max.   :608.1  
if (!empty_nodes) summary(df.cluster04)
   fecha_cnt        tmax           tmin           precip         nevada 
 Min.   :2.0   Min.   :-4.0   Min.   :-51.0   Min.   :19.0   Min.   :0  
 1st Qu.:2.0   1st Qu.: 0.0   1st Qu.:-48.0   1st Qu.:33.0   1st Qu.:0  
 Median :3.0   Median :35.0   Median :-26.0   Median :49.0   Median :0  
 Mean   :2.6   Mean   :20.6   Mean   :-32.8   Mean   :41.4   Mean   :0  
 3rd Qu.:3.0   3rd Qu.:36.0   3rd Qu.:-23.0   3rd Qu.:50.0   3rd Qu.:0  
 Max.   :3.0   Max.   :36.0   Max.   :-16.0   Max.   :56.0   Max.   :0  
   prof_nieve      longitud        latitud         altitud    
 Min.   :1017   Min.   :40.78   Min.   :-4.01   Min.   :1894  
 1st Qu.:1073   1st Qu.:40.78   1st Qu.:-4.01   1st Qu.:1894  
 Median :1168   Median :40.78   Median :-4.01   Median :1894  
 Mean   :1317   Mean   :40.78   Mean   :-4.01   Mean   :1894  
 3rd Qu.:1494   3rd Qu.:40.78   3rd Qu.:-4.01   3rd Qu.:1894  
 Max.   :1834   Max.   :40.78   Max.   :-4.01   Max.   :1894  

NĂºmero de elementos en cada clĂºster

if (!empty_nodes) {
  df.clusters.dim <- c(dim(df.cluster01)[1], dim(df.cluster02)[1], dim(df.cluster03)[1], dim(df.cluster04)[1])
  barplot(df.clusters.dim,
          names.arg = c("cluster01", "cluster02", "cluster03", "cluster04"),
          col = "steelblue1")
}

DistribuciĂ³n de los datos

if (!empty_nodes) mpr.hist(df.cluster01)

if (!empty_nodes) mpr.hist(df.cluster02)

if (!empty_nodes) mpr.hist(df.cluster03)

if (!empty_nodes) mpr.hist(df.cluster04)

if (!empty_nodes) mpr.boxplot(df.cluster01)
if (!empty_nodes) mpr.boxplot(df.cluster02)

if (!empty_nodes) mpr.boxplot(df.cluster03)

if (!empty_nodes) mpr.boxplot(df.cluster04)

LocalizaciĂ³n geogrĂ¡fica de las estaciones de medida de cada cluster

# Agrupa por longitud y latitud para rellenar el mapa con menos datos.
if (!empty_nodes) {
  df.cluster01.grouped <- mpr.group_by_geo(df.cluster01)
  df.cluster02.grouped <- mpr.group_by_geo(df.cluster02)
  df.cluster03.grouped <- mpr.group_by_geo(df.cluster03)
  df.cluster04.grouped <- mpr.group_by_geo(df.cluster04)
}
if (!empty_nodes) mpr.draw_map(spain, df.cluster01.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster02.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster03.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster04.grouped)

VisualizaciĂ³n de 5 clĂºsteres:

if (!empty_nodes) {
  plot(hac, hang=-1, labels=F)
  rect.hclust(hac, k=5)
}

VisualizaciĂ³n de los clĂºsters en el mapa

A quĂ© clĂºster pertenece cada nodo del mapa de kohonen:

if (!empty_nodes) {
  groups <- cutree(hac, k=5)
  plot(model, type="mapping",
    bgcol=c("steelblue1","sienna1","yellowgreen","red","blue","yellow","purple","green","white","#1f77b4", '#ff7f0e', '#2ca02c', '#d62728', '#9467bd', '#8c564b', '#e377c2')[groups],
    shape = "straight", labels = "")
  add.cluster.boundaries(model, clustering=groups)
}

AnĂ¡lisis de las observaciones de cada cluster

if (!empty_nodes) {
  # Asignamos a cada registro su clĂºster
  df$cluster <- groups[model$unit.classif]
}

Nuevos dataframes por cluster

if (!empty_nodes) {
  # Creo nuevos dataframes, uno por cada clĂºster.
  df.cluster01 <- subset(df, cluster==1)
  df.cluster02 <- subset(df, cluster==2)
  df.cluster03 <- subset(df, cluster==3)
  df.cluster04 <- subset(df, cluster==4)
  df.cluster05 <- subset(df, cluster==5)

  # Extraigo del dataframe las features.
  df.cluster01 <- select(df.cluster01, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster02 <- select(df.cluster02, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster03 <- select(df.cluster03, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster04 <- select(df.cluster04, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster05 <- select(df.cluster05, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
}
if (!empty_nodes) summary(df.cluster01)
   fecha_cnt           tmax            tmin            precip      
 Min.   : 1.000   Min.   :-53.0   Min.   :-121.0   Min.   :  0.00  
 1st Qu.: 4.000   1st Qu.:148.2   1st Qu.:  53.0   1st Qu.:  3.00  
 Median : 6.000   Median :198.0   Median :  98.0   Median : 10.00  
 Mean   : 6.498   Mean   :200.3   Mean   :  98.9   Mean   : 16.24  
 3rd Qu.: 9.000   3rd Qu.:255.0   3rd Qu.: 148.0   3rd Qu.: 22.00  
 Max.   :12.000   Max.   :403.0   Max.   : 254.0   Max.   :422.00  
     nevada           prof_nieve          longitud        latitud        
 Min.   :0.00e+00   Min.   :  0.0000   Min.   :27.82   Min.   :-17.8889  
 1st Qu.:0.00e+00   1st Qu.:  0.0000   1st Qu.:38.28   1st Qu.: -5.6417  
 Median :0.00e+00   Median :  0.0000   Median :40.82   Median : -3.4500  
 Mean   :3.16e-05   Mean   :  0.2657   Mean   :39.66   Mean   : -3.4350  
 3rd Qu.:0.00e+00   3rd Qu.:  0.0000   3rd Qu.:42.08   3rd Qu.:  0.4914  
 Max.   :1.00e+00   Max.   :390.0000   Max.   :43.57   Max.   :  4.2156  
    altitud      
 Min.   :   1.0  
 1st Qu.:  42.0  
 Median : 247.0  
 Mean   : 418.1  
 3rd Qu.: 656.0  
 Max.   :2535.0  
if (!empty_nodes) summary(df.cluster02)
   fecha_cnt          tmax             tmin            precip           nevada 
 Min.   :1.000   Min.   :-12.00   Min.   :-72.00   Min.   : 16.00   Min.   :0  
 1st Qu.:2.000   1st Qu.: 10.00   1st Qu.:-44.00   1st Qu.: 36.00   1st Qu.:0  
 Median :2.000   Median : 15.00   Median :-34.00   Median : 52.00   Median :0  
 Mean   :2.333   Mean   : 24.19   Mean   :-31.95   Mean   : 61.29   Mean   :0  
 3rd Qu.:3.000   3rd Qu.: 29.00   3rd Qu.:-24.00   3rd Qu.: 78.00   3rd Qu.:0  
 Max.   :4.000   Max.   : 76.00   Max.   :  8.00   Max.   :180.00   Max.   :0  
   prof_nieve       longitud        latitud         altitud    
 Min.   :415.0   Min.   :40.78   Min.   :-4.01   Min.   :1894  
 1st Qu.:503.0   1st Qu.:40.78   1st Qu.:-4.01   1st Qu.:1894  
 Median :592.0   Median :40.78   Median :-4.01   Median :1894  
 Mean   :594.6   Mean   :40.78   Mean   :-4.01   Mean   :1894  
 3rd Qu.:657.0   3rd Qu.:40.78   3rd Qu.:-4.01   3rd Qu.:1894  
 Max.   :892.0   Max.   :40.78   Max.   :-4.01   Max.   :1894  
if (!empty_nodes) summary(df.cluster03)
   fecha_cnt      tmax            tmin        precip          nevada   
 Min.   :2   Min.   :71.00   Min.   :-1   Min.   :14.00   Min.   :4.0  
 1st Qu.:2   1st Qu.:72.25   1st Qu.:-1   1st Qu.:15.25   1st Qu.:4.5  
 Median :2   Median :73.50   Median :-1   Median :16.50   Median :5.0  
 Mean   :2   Mean   :73.50   Mean   :-1   Mean   :16.50   Mean   :5.0  
 3rd Qu.:2   3rd Qu.:74.75   3rd Qu.:-1   3rd Qu.:17.75   3rd Qu.:5.5  
 Max.   :2   Max.   :76.00   Max.   :-1   Max.   :19.00   Max.   :6.0  
   prof_nieve    longitud        latitud          altitud     
 Min.   : 5   Min.   :40.48   Min.   :-3.450   Min.   :263.0  
 1st Qu.: 7   1st Qu.:40.78   1st Qu.:-2.846   1st Qu.:349.3  
 Median : 9   Median :41.08   Median :-2.242   Median :435.6  
 Mean   : 9   Mean   :41.08   Mean   :-2.242   Mean   :435.6  
 3rd Qu.:11   3rd Qu.:41.37   3rd Qu.:-1.637   3rd Qu.:521.8  
 Max.   :13   Max.   :41.67   Max.   :-1.033   Max.   :608.1  
if (!empty_nodes) summary(df.cluster04)
   fecha_cnt           tmax            tmin            precip     
 Min.   : 1.000   Min.   : 69.0   Min.   :-15.00   Min.   : 3.00  
 1st Qu.: 2.000   1st Qu.: 89.0   1st Qu.: -5.00   1st Qu.: 7.50  
 Median : 2.000   Median : 96.0   Median : 27.00   Median :12.00  
 Mean   : 6.143   Mean   :100.4   Mean   : 14.29   Mean   :11.86  
 3rd Qu.:12.000   3rd Qu.:110.0   3rd Qu.: 31.50   3rd Qu.:14.50  
 Max.   :12.000   Max.   :140.0   Max.   : 35.00   Max.   :24.00  
     nevada        prof_nieve       longitud        latitud      
 Min.   :2.000   Min.   :0.000   Min.   :40.48   Min.   :-3.450  
 1st Qu.:2.000   1st Qu.:0.000   1st Qu.:40.48   1st Qu.:-3.450  
 Median :2.000   Median :1.000   Median :41.67   Median :-1.033  
 Mean   :2.143   Mean   :1.429   Mean   :41.16   Mean   :-2.069  
 3rd Qu.:2.000   3rd Qu.:1.000   3rd Qu.:41.67   3rd Qu.:-1.033  
 Max.   :3.000   Max.   :7.000   Max.   :41.67   Max.   :-1.033  
    altitud     
 Min.   :263.0  
 1st Qu.:263.0  
 Median :263.0  
 Mean   :410.9  
 3rd Qu.:608.1  
 Max.   :608.1  
if (!empty_nodes) summary(df.cluster05)
   fecha_cnt        tmax           tmin           precip         nevada 
 Min.   :2.0   Min.   :-4.0   Min.   :-51.0   Min.   :19.0   Min.   :0  
 1st Qu.:2.0   1st Qu.: 0.0   1st Qu.:-48.0   1st Qu.:33.0   1st Qu.:0  
 Median :3.0   Median :35.0   Median :-26.0   Median :49.0   Median :0  
 Mean   :2.6   Mean   :20.6   Mean   :-32.8   Mean   :41.4   Mean   :0  
 3rd Qu.:3.0   3rd Qu.:36.0   3rd Qu.:-23.0   3rd Qu.:50.0   3rd Qu.:0  
 Max.   :3.0   Max.   :36.0   Max.   :-16.0   Max.   :56.0   Max.   :0  
   prof_nieve      longitud        latitud         altitud    
 Min.   :1017   Min.   :40.78   Min.   :-4.01   Min.   :1894  
 1st Qu.:1073   1st Qu.:40.78   1st Qu.:-4.01   1st Qu.:1894  
 Median :1168   Median :40.78   Median :-4.01   Median :1894  
 Mean   :1317   Mean   :40.78   Mean   :-4.01   Mean   :1894  
 3rd Qu.:1494   3rd Qu.:40.78   3rd Qu.:-4.01   3rd Qu.:1894  
 Max.   :1834   Max.   :40.78   Max.   :-4.01   Max.   :1894  

NĂºmero de elementos en cada clĂºster

if (!empty_nodes) {
  df.clusters.dim <- c(dim(df.cluster01)[1], dim(df.cluster02)[1], dim(df.cluster03)[1], dim(df.cluster04)[1], dim(df.cluster05)[1])
  barplot(df.clusters.dim,
          names.arg = c("cluster01", "cluster02", "cluster03", "cluster04", "cluster05"),
          col = "steelblue1")
}

DistribuciĂ³n de los datos

if (!empty_nodes) mpr.hist(df.cluster01)

if (!empty_nodes) mpr.hist(df.cluster02)

if (!empty_nodes) mpr.hist(df.cluster03)

if (!empty_nodes) mpr.hist(df.cluster04)

if (!empty_nodes) mpr.hist(df.cluster05)

if (!empty_nodes) mpr.boxplot(df.cluster01)
if (!empty_nodes) mpr.boxplot(df.cluster02)

if (!empty_nodes) mpr.boxplot(df.cluster03)

if (!empty_nodes) mpr.boxplot(df.cluster04)

if (!empty_nodes) mpr.boxplot(df.cluster05)

LocalizaciĂ³n geogrĂ¡fica de las estaciones de medida de cada cluster

# Agrupa por longitud y latitud para rellenar el mapa con menos datos.
if (!empty_nodes) {
  df.cluster01.grouped <- mpr.group_by_geo(df.cluster01)
  df.cluster02.grouped <- mpr.group_by_geo(df.cluster02)
  df.cluster03.grouped <- mpr.group_by_geo(df.cluster03)
  df.cluster04.grouped <- mpr.group_by_geo(df.cluster04)
  df.cluster05.grouped <- mpr.group_by_geo(df.cluster05)
}
if (!empty_nodes) mpr.draw_map(spain, df.cluster01.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster02.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster03.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster04.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster05.grouped)

VisualizaciĂ³n de 6 clĂºsteres:

if (!empty_nodes) {
  plot(hac, hang=-1, labels=F)
  rect.hclust(hac, k=6)
}

VisualizaciĂ³n de los clĂºsters en el mapa

A quĂ© clĂºster pertenece cada nodo del mapa de kohonen:

if (!empty_nodes) {
  groups <- cutree(hac, k=6)
  plot(model, type="mapping",
    bgcol=c("steelblue1","sienna1","yellowgreen","red","blue","yellow","purple","green","white","#1f77b4", '#ff7f0e', '#2ca02c', '#d62728', '#9467bd', '#8c564b', '#e377c2')[groups],
    shape = "straight", labels = "")
  add.cluster.boundaries(model, clustering=groups)
}

AnĂ¡lisis de las observaciones de cada cluster

if (!empty_nodes) {
  # Asignamos a cada registro su clĂºster
  df$cluster <- groups[model$unit.classif]
}

Nuevos dataframes por cluster

if (!empty_nodes) {
  # Creo nuevos dataframes, uno por cada clĂºster.
  df.cluster01 <- subset(df, cluster==1)
  df.cluster02 <- subset(df, cluster==2)
  df.cluster03 <- subset(df, cluster==3)
  df.cluster04 <- subset(df, cluster==4)
  df.cluster05 <- subset(df, cluster==5)
  df.cluster06 <- subset(df, cluster==6)

  # Extraigo del dataframe las features.
  df.cluster01 <- select(df.cluster01, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster02 <- select(df.cluster02, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster03 <- select(df.cluster03, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster04 <- select(df.cluster04, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster05 <- select(df.cluster05, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster06 <- select(df.cluster06, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
}
if (!empty_nodes) summary(df.cluster01)
   fecha_cnt           tmax            tmin            precip           nevada 
 Min.   : 1.000   Min.   :-53.0   Min.   :-121.0   Min.   :  0.00   Min.   :0  
 1st Qu.: 4.000   1st Qu.:149.0   1st Qu.:  53.0   1st Qu.:  3.00   1st Qu.:0  
 Median : 6.000   Median :198.0   Median :  98.0   Median : 10.00   Median :0  
 Mean   : 6.498   Mean   :200.3   Mean   :  98.9   Mean   : 16.24   Mean   :0  
 3rd Qu.: 9.000   3rd Qu.:255.0   3rd Qu.: 148.0   3rd Qu.: 22.00   3rd Qu.:0  
 Max.   :12.000   Max.   :403.0   Max.   : 254.0   Max.   :422.00   Max.   :0  
   prof_nieve          longitud        latitud            altitud      
 Min.   :  0.0000   Min.   :27.82   Min.   :-17.8889   Min.   :   1.0  
 1st Qu.:  0.0000   1st Qu.:38.28   1st Qu.: -5.6417   1st Qu.:  42.0  
 Median :  0.0000   Median :40.82   Median : -3.4500   Median : 247.0  
 Mean   :  0.2657   Mean   :39.66   Mean   : -3.4350   Mean   : 418.1  
 3rd Qu.:  0.0000   3rd Qu.:42.08   3rd Qu.:  0.4914   3rd Qu.: 656.0  
 Max.   :390.0000   Max.   :43.57   Max.   :  4.2156   Max.   :2535.0  
if (!empty_nodes) summary(df.cluster02)
   fecha_cnt          tmax             tmin            precip           nevada 
 Min.   :1.000   Min.   :-12.00   Min.   :-72.00   Min.   : 16.00   Min.   :0  
 1st Qu.:2.000   1st Qu.: 10.00   1st Qu.:-44.00   1st Qu.: 36.00   1st Qu.:0  
 Median :2.000   Median : 15.00   Median :-34.00   Median : 52.00   Median :0  
 Mean   :2.333   Mean   : 24.19   Mean   :-31.95   Mean   : 61.29   Mean   :0  
 3rd Qu.:3.000   3rd Qu.: 29.00   3rd Qu.:-24.00   3rd Qu.: 78.00   3rd Qu.:0  
 Max.   :4.000   Max.   : 76.00   Max.   :  8.00   Max.   :180.00   Max.   :0  
   prof_nieve       longitud        latitud         altitud    
 Min.   :415.0   Min.   :40.78   Min.   :-4.01   Min.   :1894  
 1st Qu.:503.0   1st Qu.:40.78   1st Qu.:-4.01   1st Qu.:1894  
 Median :592.0   Median :40.78   Median :-4.01   Median :1894  
 Mean   :594.6   Mean   :40.78   Mean   :-4.01   Mean   :1894  
 3rd Qu.:657.0   3rd Qu.:40.78   3rd Qu.:-4.01   3rd Qu.:1894  
 Max.   :892.0   Max.   :40.78   Max.   :-4.01   Max.   :1894  
if (!empty_nodes) summary(df.cluster03)
   fecha_cnt      tmax            tmin        precip          nevada   
 Min.   :2   Min.   :71.00   Min.   :-1   Min.   :14.00   Min.   :4.0  
 1st Qu.:2   1st Qu.:72.25   1st Qu.:-1   1st Qu.:15.25   1st Qu.:4.5  
 Median :2   Median :73.50   Median :-1   Median :16.50   Median :5.0  
 Mean   :2   Mean   :73.50   Mean   :-1   Mean   :16.50   Mean   :5.0  
 3rd Qu.:2   3rd Qu.:74.75   3rd Qu.:-1   3rd Qu.:17.75   3rd Qu.:5.5  
 Max.   :2   Max.   :76.00   Max.   :-1   Max.   :19.00   Max.   :6.0  
   prof_nieve    longitud        latitud          altitud     
 Min.   : 5   Min.   :40.48   Min.   :-3.450   Min.   :263.0  
 1st Qu.: 7   1st Qu.:40.78   1st Qu.:-2.846   1st Qu.:349.3  
 Median : 9   Median :41.08   Median :-2.242   Median :435.6  
 Mean   : 9   Mean   :41.08   Mean   :-2.242   Mean   :435.6  
 3rd Qu.:11   3rd Qu.:41.37   3rd Qu.:-1.637   3rd Qu.:521.8  
 Max.   :13   Max.   :41.67   Max.   :-1.033   Max.   :608.1  
if (!empty_nodes) summary(df.cluster04)
   fecha_cnt           tmax            tmin            precip     
 Min.   : 1.000   Min.   : 69.0   Min.   :-15.00   Min.   : 3.00  
 1st Qu.: 2.000   1st Qu.: 89.0   1st Qu.: -5.00   1st Qu.: 7.50  
 Median : 2.000   Median : 96.0   Median : 27.00   Median :12.00  
 Mean   : 6.143   Mean   :100.4   Mean   : 14.29   Mean   :11.86  
 3rd Qu.:12.000   3rd Qu.:110.0   3rd Qu.: 31.50   3rd Qu.:14.50  
 Max.   :12.000   Max.   :140.0   Max.   : 35.00   Max.   :24.00  
     nevada        prof_nieve       longitud        latitud      
 Min.   :2.000   Min.   :0.000   Min.   :40.48   Min.   :-3.450  
 1st Qu.:2.000   1st Qu.:0.000   1st Qu.:40.48   1st Qu.:-3.450  
 Median :2.000   Median :1.000   Median :41.67   Median :-1.033  
 Mean   :2.143   Mean   :1.429   Mean   :41.16   Mean   :-2.069  
 3rd Qu.:2.000   3rd Qu.:1.000   3rd Qu.:41.67   3rd Qu.:-1.033  
 Max.   :3.000   Max.   :7.000   Max.   :41.67   Max.   :-1.033  
    altitud     
 Min.   :263.0  
 1st Qu.:263.0  
 Median :263.0  
 Mean   :410.9  
 3rd Qu.:608.1  
 Max.   :608.1  
if (!empty_nodes) summary(df.cluster05)
   fecha_cnt        tmax           tmin           precip         nevada 
 Min.   :2.0   Min.   :-4.0   Min.   :-51.0   Min.   :19.0   Min.   :0  
 1st Qu.:2.0   1st Qu.: 0.0   1st Qu.:-48.0   1st Qu.:33.0   1st Qu.:0  
 Median :3.0   Median :35.0   Median :-26.0   Median :49.0   Median :0  
 Mean   :2.6   Mean   :20.6   Mean   :-32.8   Mean   :41.4   Mean   :0  
 3rd Qu.:3.0   3rd Qu.:36.0   3rd Qu.:-23.0   3rd Qu.:50.0   3rd Qu.:0  
 Max.   :3.0   Max.   :36.0   Max.   :-16.0   Max.   :56.0   Max.   :0  
   prof_nieve      longitud        latitud         altitud    
 Min.   :1017   Min.   :40.78   Min.   :-4.01   Min.   :1894  
 1st Qu.:1073   1st Qu.:40.78   1st Qu.:-4.01   1st Qu.:1894  
 Median :1168   Median :40.78   Median :-4.01   Median :1894  
 Mean   :1317   Mean   :40.78   Mean   :-4.01   Mean   :1894  
 3rd Qu.:1494   3rd Qu.:40.78   3rd Qu.:-4.01   3rd Qu.:1894  
 Max.   :1834   Max.   :40.78   Max.   :-4.01   Max.   :1894  
if (!empty_nodes) summary(df.cluster06)
   fecha_cnt           tmax            tmin           precip          nevada 
 Min.   : 1.000   Min.   :86.00   Min.   :-24.0   Min.   : 6.00   Min.   :1  
 1st Qu.: 6.500   1st Qu.:86.00   1st Qu.:-19.5   1st Qu.: 6.00   1st Qu.:1  
 Median :12.000   Median :86.00   Median :-15.0   Median : 6.00   Median :1  
 Mean   : 8.333   Mean   :88.33   Mean   : -7.0   Mean   :10.33   Mean   :1  
 3rd Qu.:12.000   3rd Qu.:89.50   3rd Qu.:  1.5   3rd Qu.:12.50   3rd Qu.:1  
 Max.   :12.000   Max.   :93.00   Max.   : 18.0   Max.   :19.00   Max.   :1  
   prof_nieve        longitud        latitud          altitud     
 Min.   :0.0000   Min.   :40.48   Min.   :-3.450   Min.   :263.0  
 1st Qu.:0.0000   1st Qu.:40.48   1st Qu.:-3.450   1st Qu.:435.6  
 Median :0.0000   Median :40.48   Median :-3.450   Median :608.1  
 Mean   :0.3333   Mean   :40.88   Mean   :-2.644   Mean   :493.1  
 3rd Qu.:0.5000   3rd Qu.:41.08   3rd Qu.:-2.242   3rd Qu.:608.1  
 Max.   :1.0000   Max.   :41.67   Max.   :-1.033   Max.   :608.1  

NĂºmero de elementos en cada clĂºster

if (!empty_nodes) {
  df.clusters.dim <- c(dim(df.cluster01)[1], dim(df.cluster02)[1], dim(df.cluster03)[1], dim(df.cluster04)[1], dim(df.cluster05)[1], dim(df.cluster06)[1])
  barplot(df.clusters.dim,
          names.arg = c("cluster01", "cluster02", "cluster03", "cluster04", "cluster05", "cluster06"),
          col = "steelblue1")
}

DistribuciĂ³n de los datos

if (!empty_nodes) mpr.hist(df.cluster01)

if (!empty_nodes) mpr.hist(df.cluster02)

if (!empty_nodes) mpr.hist(df.cluster03)

if (!empty_nodes) mpr.hist(df.cluster04)

if (!empty_nodes) mpr.hist(df.cluster05)

if (!empty_nodes) mpr.hist(df.cluster06)

if (!empty_nodes) mpr.boxplot(df.cluster01)
if (!empty_nodes) mpr.boxplot(df.cluster02)

if (!empty_nodes) mpr.boxplot(df.cluster03)

if (!empty_nodes) mpr.boxplot(df.cluster04)

if (!empty_nodes) mpr.boxplot(df.cluster05)

if (!empty_nodes) mpr.boxplot(df.cluster06)

LocalizaciĂ³n geogrĂ¡fica de las estaciones de medida de cada cluster

# Agrupa por longitud y latitud para rellenar el mapa con menos datos.
if (!empty_nodes) {
  df.cluster01.grouped <- mpr.group_by_geo(df.cluster01)
  df.cluster02.grouped <- mpr.group_by_geo(df.cluster02)
  df.cluster03.grouped <- mpr.group_by_geo(df.cluster03)
  df.cluster04.grouped <- mpr.group_by_geo(df.cluster04)
  df.cluster05.grouped <- mpr.group_by_geo(df.cluster05)
  df.cluster06.grouped <- mpr.group_by_geo(df.cluster06)
}
if (!empty_nodes) mpr.draw_map(spain, df.cluster01.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster02.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster03.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster04.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster05.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster06.grouped)

VisualizaciĂ³n de 8 clĂºsteres:

if (!empty_nodes) {
  plot(hac, hang=-1, labels=F)
  rect.hclust(hac, k=8)
}

VisualizaciĂ³n de los clĂºsters en el mapa

A quĂ© clĂºster pertenece cada nodo del mapa de kohonen:

if (!empty_nodes) {
  groups <- cutree(hac, k=8)
  plot(model, type="mapping",
    bgcol=c("steelblue1","sienna1","yellowgreen","red","blue","yellow","purple","green","white","#1f77b4", '#ff7f0e', '#2ca02c', '#d62728', '#9467bd', '#8c564b', '#e377c2')[groups],
    shape = "straight", labels = "")
  add.cluster.boundaries(model, clustering=groups)
}

AnĂ¡lisis de las observaciones de cada cluster

if (!empty_nodes) {
  # Asignamos a cada registro su clĂºster
  df$cluster <- groups[model$unit.classif]
}

Nuevos dataframes por cluster

if (!empty_nodes) {
  # Creo nuevos dataframes, uno por cada clĂºster.
  df.cluster01 <- subset(df, cluster==1)
  df.cluster02 <- subset(df, cluster==2)
  df.cluster03 <- subset(df, cluster==3)
  df.cluster04 <- subset(df, cluster==4)
  df.cluster05 <- subset(df, cluster==5)
  df.cluster06 <- subset(df, cluster==6)
  df.cluster07 <- subset(df, cluster==7)
  df.cluster08 <- subset(df, cluster==8)

  # Extraigo del dataframe las features.
  df.cluster01 <- select(df.cluster01, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster02 <- select(df.cluster02, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster03 <- select(df.cluster03, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster04 <- select(df.cluster04, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster05 <- select(df.cluster05, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster06 <- select(df.cluster06, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster07 <- select(df.cluster07, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster08 <- select(df.cluster08, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
}
if (!empty_nodes) summary(df.cluster01)
   fecha_cnt           tmax            tmin            precip          nevada 
 Min.   : 1.000   Min.   : -8.0   Min.   :-58.00   Min.   :155.0   Min.   :0  
 1st Qu.: 2.000   1st Qu.:109.0   1st Qu.: 50.00   1st Qu.:166.0   1st Qu.:0  
 Median :10.000   Median :130.0   Median : 72.00   Median :184.0   Median :0  
 Mean   : 7.412   Mean   :140.1   Mean   : 76.28   Mean   :198.6   Mean   :0  
 3rd Qu.:11.000   3rd Qu.:151.0   3rd Qu.: 92.00   3rd Qu.:218.0   3rd Qu.:0  
 Max.   :12.000   Max.   :350.0   Max.   :223.00   Max.   :422.0   Max.   :0  
   prof_nieve        longitud        latitud           altitud      
 Min.   : 0.000   Min.   :28.31   Min.   :-16.499   Min.   :   4.0  
 1st Qu.: 0.000   1st Qu.:40.78   1st Qu.: -8.624   1st Qu.:  91.1  
 Median : 0.000   Median :42.24   Median : -8.411   Median : 261.0  
 Mean   : 1.196   Mean   :40.88   Mean   : -6.418   Mean   : 507.9  
 3rd Qu.: 0.000   3rd Qu.:42.89   3rd Qu.: -3.174   3rd Qu.: 370.0  
 Max.   :81.000   Max.   :43.46   Max.   :  2.825   Max.   :2400.0  
if (!empty_nodes) summary(df.cluster02)
   fecha_cnt           tmax            tmin             precip      
 Min.   : 1.000   Min.   :-53.0   Min.   :-121.00   Min.   :  0.00  
 1st Qu.: 4.000   1st Qu.:149.0   1st Qu.:  53.00   1st Qu.:  3.00  
 Median : 6.000   Median :198.0   Median :  98.00   Median : 10.00  
 Mean   : 6.499   Mean   :200.5   Mean   :  99.02   Mean   : 16.03  
 3rd Qu.: 9.000   3rd Qu.:255.0   3rd Qu.: 148.00   3rd Qu.: 22.00  
 Max.   :12.000   Max.   :403.0   Max.   : 254.00   Max.   :154.00  
     nevada    prof_nieve          longitud        latitud        
 Min.   :0   Min.   :  0.0000   Min.   :27.82   Min.   :-17.8889  
 1st Qu.:0   1st Qu.:  0.0000   1st Qu.:38.28   1st Qu.: -5.6417  
 Median :0   Median :  0.0000   Median :40.82   Median : -3.4500  
 Mean   :0   Mean   :  0.1038   Mean   :39.66   Mean   : -3.4315  
 3rd Qu.:0   3rd Qu.:  0.0000   3rd Qu.:42.08   3rd Qu.:  0.4914  
 Max.   :0   Max.   :104.0000   Max.   :43.57   Max.   :  4.2156  
    altitud      
 Min.   :   1.0  
 1st Qu.:  42.0  
 Median : 247.0  
 Mean   : 416.9  
 3rd Qu.: 656.0  
 Max.   :2535.0  
if (!empty_nodes) summary(df.cluster03)
   fecha_cnt          tmax             tmin            precip           nevada 
 Min.   :1.000   Min.   :-12.00   Min.   :-72.00   Min.   : 16.00   Min.   :0  
 1st Qu.:2.000   1st Qu.: 10.00   1st Qu.:-44.00   1st Qu.: 36.00   1st Qu.:0  
 Median :2.000   Median : 15.00   Median :-34.00   Median : 52.00   Median :0  
 Mean   :2.333   Mean   : 24.19   Mean   :-31.95   Mean   : 61.29   Mean   :0  
 3rd Qu.:3.000   3rd Qu.: 29.00   3rd Qu.:-24.00   3rd Qu.: 78.00   3rd Qu.:0  
 Max.   :4.000   Max.   : 76.00   Max.   :  8.00   Max.   :180.00   Max.   :0  
   prof_nieve       longitud        latitud         altitud    
 Min.   :415.0   Min.   :40.78   Min.   :-4.01   Min.   :1894  
 1st Qu.:503.0   1st Qu.:40.78   1st Qu.:-4.01   1st Qu.:1894  
 Median :592.0   Median :40.78   Median :-4.01   Median :1894  
 Mean   :594.6   Mean   :40.78   Mean   :-4.01   Mean   :1894  
 3rd Qu.:657.0   3rd Qu.:40.78   3rd Qu.:-4.01   3rd Qu.:1894  
 Max.   :892.0   Max.   :40.78   Max.   :-4.01   Max.   :1894  
if (!empty_nodes) summary(df.cluster04)
   fecha_cnt      tmax            tmin        precip          nevada   
 Min.   :2   Min.   :71.00   Min.   :-1   Min.   :14.00   Min.   :4.0  
 1st Qu.:2   1st Qu.:72.25   1st Qu.:-1   1st Qu.:15.25   1st Qu.:4.5  
 Median :2   Median :73.50   Median :-1   Median :16.50   Median :5.0  
 Mean   :2   Mean   :73.50   Mean   :-1   Mean   :16.50   Mean   :5.0  
 3rd Qu.:2   3rd Qu.:74.75   3rd Qu.:-1   3rd Qu.:17.75   3rd Qu.:5.5  
 Max.   :2   Max.   :76.00   Max.   :-1   Max.   :19.00   Max.   :6.0  
   prof_nieve    longitud        latitud          altitud     
 Min.   : 5   Min.   :40.48   Min.   :-3.450   Min.   :263.0  
 1st Qu.: 7   1st Qu.:40.78   1st Qu.:-2.846   1st Qu.:349.3  
 Median : 9   Median :41.08   Median :-2.242   Median :435.6  
 Mean   : 9   Mean   :41.08   Mean   :-2.242   Mean   :435.6  
 3rd Qu.:11   3rd Qu.:41.37   3rd Qu.:-1.637   3rd Qu.:521.8  
 Max.   :13   Max.   :41.67   Max.   :-1.033   Max.   :608.1  
if (!empty_nodes) summary(df.cluster05)
   fecha_cnt           tmax             tmin            precip      
 Min.   : 1.000   Min.   :-12.00   Min.   :-63.00   Min.   :  2.00  
 1st Qu.: 1.000   1st Qu.: 16.00   1st Qu.:-35.00   1st Qu.: 29.00  
 Median : 2.000   Median : 34.00   Median :-23.00   Median : 43.00  
 Mean   : 3.685   Mean   : 36.15   Mean   :-22.38   Mean   : 47.01  
 3rd Qu.: 4.000   3rd Qu.: 49.00   3rd Qu.: -8.00   3rd Qu.: 67.00  
 Max.   :12.000   Max.   : 99.00   Max.   : 28.00   Max.   :126.00  
     nevada    prof_nieve       longitud        latitud         altitud    
 Min.   :0   Min.   :106.0   Min.   :40.78   Min.   :-4.01   Min.   :1894  
 1st Qu.:0   1st Qu.:144.0   1st Qu.:40.78   1st Qu.:-4.01   1st Qu.:1894  
 Median :0   Median :197.0   Median :40.78   Median :-4.01   Median :1894  
 Mean   :0   Mean   :209.1   Mean   :40.78   Mean   :-4.01   Mean   :1894  
 3rd Qu.:0   3rd Qu.:259.0   3rd Qu.:40.78   3rd Qu.:-4.01   3rd Qu.:1894  
 Max.   :0   Max.   :390.0   Max.   :40.78   Max.   :-4.01   Max.   :1894  
if (!empty_nodes) summary(df.cluster06)
   fecha_cnt           tmax            tmin            precip     
 Min.   : 1.000   Min.   : 69.0   Min.   :-15.00   Min.   : 3.00  
 1st Qu.: 2.000   1st Qu.: 89.0   1st Qu.: -5.00   1st Qu.: 7.50  
 Median : 2.000   Median : 96.0   Median : 27.00   Median :12.00  
 Mean   : 6.143   Mean   :100.4   Mean   : 14.29   Mean   :11.86  
 3rd Qu.:12.000   3rd Qu.:110.0   3rd Qu.: 31.50   3rd Qu.:14.50  
 Max.   :12.000   Max.   :140.0   Max.   : 35.00   Max.   :24.00  
     nevada        prof_nieve       longitud        latitud      
 Min.   :2.000   Min.   :0.000   Min.   :40.48   Min.   :-3.450  
 1st Qu.:2.000   1st Qu.:0.000   1st Qu.:40.48   1st Qu.:-3.450  
 Median :2.000   Median :1.000   Median :41.67   Median :-1.033  
 Mean   :2.143   Mean   :1.429   Mean   :41.16   Mean   :-2.069  
 3rd Qu.:2.000   3rd Qu.:1.000   3rd Qu.:41.67   3rd Qu.:-1.033  
 Max.   :3.000   Max.   :7.000   Max.   :41.67   Max.   :-1.033  
    altitud     
 Min.   :263.0  
 1st Qu.:263.0  
 Median :263.0  
 Mean   :410.9  
 3rd Qu.:608.1  
 Max.   :608.1  
if (!empty_nodes) summary(df.cluster07)
   fecha_cnt        tmax           tmin           precip         nevada 
 Min.   :2.0   Min.   :-4.0   Min.   :-51.0   Min.   :19.0   Min.   :0  
 1st Qu.:2.0   1st Qu.: 0.0   1st Qu.:-48.0   1st Qu.:33.0   1st Qu.:0  
 Median :3.0   Median :35.0   Median :-26.0   Median :49.0   Median :0  
 Mean   :2.6   Mean   :20.6   Mean   :-32.8   Mean   :41.4   Mean   :0  
 3rd Qu.:3.0   3rd Qu.:36.0   3rd Qu.:-23.0   3rd Qu.:50.0   3rd Qu.:0  
 Max.   :3.0   Max.   :36.0   Max.   :-16.0   Max.   :56.0   Max.   :0  
   prof_nieve      longitud        latitud         altitud    
 Min.   :1017   Min.   :40.78   Min.   :-4.01   Min.   :1894  
 1st Qu.:1073   1st Qu.:40.78   1st Qu.:-4.01   1st Qu.:1894  
 Median :1168   Median :40.78   Median :-4.01   Median :1894  
 Mean   :1317   Mean   :40.78   Mean   :-4.01   Mean   :1894  
 3rd Qu.:1494   3rd Qu.:40.78   3rd Qu.:-4.01   3rd Qu.:1894  
 Max.   :1834   Max.   :40.78   Max.   :-4.01   Max.   :1894  
if (!empty_nodes) summary(df.cluster08)
   fecha_cnt           tmax            tmin           precip          nevada 
 Min.   : 1.000   Min.   :86.00   Min.   :-24.0   Min.   : 6.00   Min.   :1  
 1st Qu.: 6.500   1st Qu.:86.00   1st Qu.:-19.5   1st Qu.: 6.00   1st Qu.:1  
 Median :12.000   Median :86.00   Median :-15.0   Median : 6.00   Median :1  
 Mean   : 8.333   Mean   :88.33   Mean   : -7.0   Mean   :10.33   Mean   :1  
 3rd Qu.:12.000   3rd Qu.:89.50   3rd Qu.:  1.5   3rd Qu.:12.50   3rd Qu.:1  
 Max.   :12.000   Max.   :93.00   Max.   : 18.0   Max.   :19.00   Max.   :1  
   prof_nieve        longitud        latitud          altitud     
 Min.   :0.0000   Min.   :40.48   Min.   :-3.450   Min.   :263.0  
 1st Qu.:0.0000   1st Qu.:40.48   1st Qu.:-3.450   1st Qu.:435.6  
 Median :0.0000   Median :40.48   Median :-3.450   Median :608.1  
 Mean   :0.3333   Mean   :40.88   Mean   :-2.644   Mean   :493.1  
 3rd Qu.:0.5000   3rd Qu.:41.08   3rd Qu.:-2.242   3rd Qu.:608.1  
 Max.   :1.0000   Max.   :41.67   Max.   :-1.033   Max.   :608.1  

NĂºmero de elementos en cada clĂºster

if (!empty_nodes) {
  df.clusters.dim <- c(dim(df.cluster01)[1], dim(df.cluster02)[1], dim(df.cluster03)[1], dim(df.cluster04)[1], dim(df.cluster05)[1], dim(df.cluster06)[1], dim(df.cluster07)[1], dim(df.cluster08)[1])
  barplot(df.clusters.dim,
          names.arg = c("cluster01", "cluster02", "cluster03", "cluster04", "cluster05", "cluster06", "cluster07", "cluster08"),
          col = "steelblue1")
}

DistribuciĂ³n de los datos

if (!empty_nodes) mpr.hist(df.cluster01)

if (!empty_nodes) mpr.hist(df.cluster02)

if (!empty_nodes) mpr.hist(df.cluster03)

if (!empty_nodes) mpr.hist(df.cluster04)

if (!empty_nodes) mpr.hist(df.cluster05)

if (!empty_nodes) mpr.hist(df.cluster06)

if (!empty_nodes) mpr.hist(df.cluster07)

if (!empty_nodes) mpr.hist(df.cluster08)

if (!empty_nodes) mpr.boxplot(df.cluster01)
if (!empty_nodes) mpr.boxplot(df.cluster02)

if (!empty_nodes) mpr.boxplot(df.cluster03)

if (!empty_nodes) mpr.boxplot(df.cluster04)

if (!empty_nodes) mpr.boxplot(df.cluster05)

if (!empty_nodes) mpr.boxplot(df.cluster06)

if (!empty_nodes) mpr.boxplot(df.cluster07)

if (!empty_nodes) mpr.boxplot(df.cluster08)

LocalizaciĂ³n geogrĂ¡fica de las estaciones de medida de cada cluster

# Agrupa por longitud y latitud para rellenar el mapa con menos datos.
if (!empty_nodes) {
  df.cluster01.grouped <- mpr.group_by_geo(df.cluster01)
  df.cluster02.grouped <- mpr.group_by_geo(df.cluster02)
  df.cluster03.grouped <- mpr.group_by_geo(df.cluster03)
  df.cluster04.grouped <- mpr.group_by_geo(df.cluster04)
  df.cluster05.grouped <- mpr.group_by_geo(df.cluster05)
  df.cluster06.grouped <- mpr.group_by_geo(df.cluster06)
  df.cluster07.grouped <- mpr.group_by_geo(df.cluster07)
  df.cluster08.grouped <- mpr.group_by_geo(df.cluster08)
}
if (!empty_nodes) mpr.draw_map(spain, df.cluster01.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster02.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster03.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster04.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster05.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster06.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster07.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster08.grouped)

VisualizaciĂ³n de 10 clĂºsteres:

if (!empty_nodes) {
  plot(hac, hang=-1, labels=F)
  rect.hclust(hac, k=10)
}

VisualizaciĂ³n de los clĂºsters en el mapa

A quĂ© clĂºster pertenece cada nodo del mapa de kohonen:

if (!empty_nodes) {
  groups <- cutree(hac, k=10)
  plot(model, type="mapping",
    bgcol=c("steelblue1","sienna1","yellowgreen","red","blue","yellow","purple","green","white","#1f77b4", '#ff7f0e', '#2ca02c', '#d62728', '#9467bd', '#8c564b', '#e377c2')[groups],
    shape = "straight", labels = "")
  add.cluster.boundaries(model, clustering=groups)
}

AnĂ¡lisis de las observaciones de cada cluster

if (!empty_nodes) {
  # Asignamos a cada registro su clĂºster
  df$cluster <- groups[model$unit.classif]
}

Nuevos dataframes por cluster

if (!empty_nodes) {
  # Creo nuevos dataframes, uno por cada clĂºster.
  df.cluster01 <- subset(df, cluster==1)
  df.cluster02 <- subset(df, cluster==2)
  df.cluster03 <- subset(df, cluster==3)
  df.cluster04 <- subset(df, cluster==4)
  df.cluster05 <- subset(df, cluster==5)
  df.cluster06 <- subset(df, cluster==6)
  df.cluster07 <- subset(df, cluster==7)
  df.cluster08 <- subset(df, cluster==8)
  df.cluster09 <- subset(df, cluster==9)
  df.cluster10 <- subset(df, cluster==10)

  # Extraigo del dataframe las features.
  df.cluster01 <- select(df.cluster01, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster02 <- select(df.cluster02, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster03 <- select(df.cluster03, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster04 <- select(df.cluster04, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster05 <- select(df.cluster05, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster06 <- select(df.cluster06, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster07 <- select(df.cluster07, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster08 <- select(df.cluster08, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster09 <- select(df.cluster09, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster10 <- select(df.cluster10, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
}
if (!empty_nodes) summary(df.cluster01)
   fecha_cnt           tmax            tmin            precip          nevada 
 Min.   : 1.000   Min.   : -8.0   Min.   :-58.00   Min.   :155.0   Min.   :0  
 1st Qu.: 2.000   1st Qu.:109.0   1st Qu.: 50.00   1st Qu.:166.0   1st Qu.:0  
 Median :10.000   Median :130.0   Median : 72.00   Median :184.0   Median :0  
 Mean   : 7.412   Mean   :140.1   Mean   : 76.28   Mean   :198.6   Mean   :0  
 3rd Qu.:11.000   3rd Qu.:151.0   3rd Qu.: 92.00   3rd Qu.:218.0   3rd Qu.:0  
 Max.   :12.000   Max.   :350.0   Max.   :223.00   Max.   :422.0   Max.   :0  
   prof_nieve        longitud        latitud           altitud      
 Min.   : 0.000   Min.   :28.31   Min.   :-16.499   Min.   :   4.0  
 1st Qu.: 0.000   1st Qu.:40.78   1st Qu.: -8.624   1st Qu.:  91.1  
 Median : 0.000   Median :42.24   Median : -8.411   Median : 261.0  
 Mean   : 1.196   Mean   :40.88   Mean   : -6.418   Mean   : 507.9  
 3rd Qu.: 0.000   3rd Qu.:42.89   3rd Qu.: -3.174   3rd Qu.: 370.0  
 Max.   :81.000   Max.   :43.46   Max.   :  2.825   Max.   :2400.0  
if (!empty_nodes) summary(df.cluster02)
   fecha_cnt           tmax            tmin             precip      
 Min.   : 1.000   Min.   :-42.0   Min.   :-102.00   Min.   : 45.00  
 1st Qu.: 3.000   1st Qu.:122.0   1st Qu.:  51.00   1st Qu.: 58.00  
 Median : 9.000   Median :145.0   Median :  73.00   Median : 67.00  
 Mean   : 7.051   Mean   :150.3   Mean   :  77.45   Mean   : 73.76  
 3rd Qu.:11.000   3rd Qu.:176.2   3rd Qu.: 102.00   3rd Qu.: 84.00  
 Max.   :12.000   Max.   :336.0   Max.   : 219.00   Max.   :154.00  
     nevada    prof_nieve         longitud        latitud       
 Min.   :0   Min.   : 0.0000   Min.   :27.82   Min.   :-17.889  
 1st Qu.:0   1st Qu.: 0.0000   1st Qu.:41.15   1st Qu.: -8.372  
 Median :0   Median : 0.0000   Median :42.53   Median : -4.010  
 Mean   :0   Mean   : 0.2393   Mean   :41.48   Mean   : -4.397  
 3rd Qu.:0   3rd Qu.: 0.0000   3rd Qu.:43.31   3rd Qu.: -1.787  
 Max.   :0   Max.   :79.0000   Max.   :43.57   Max.   :  4.216  
    altitud      
 Min.   :   1.0  
 1st Qu.:  42.0  
 Median : 127.0  
 Mean   : 341.4  
 3rd Qu.: 370.0  
 Max.   :2535.0  
if (!empty_nodes) summary(df.cluster03)
   fecha_cnt           tmax            tmin           precip          nevada 
 Min.   : 1.000   Min.   :109.0   Min.   : 21.0   Min.   : 0.00   Min.   :0  
 1st Qu.: 5.000   1st Qu.:212.0   1st Qu.:110.0   1st Qu.: 1.00   1st Qu.:0  
 Median : 7.000   Median :246.0   Median :141.0   Median : 8.00   Median :0  
 Mean   : 7.115   Mean   :247.4   Mean   :141.2   Mean   :13.08   Mean   :0  
 3rd Qu.: 9.000   3rd Qu.:284.0   3rd Qu.:171.0   3rd Qu.:20.00   3rd Qu.:0  
 Max.   :12.000   Max.   :403.0   Max.   :254.0   Max.   :63.00   Max.   :0  
   prof_nieve          longitud        latitud            altitud      
 Min.   : 0.00000   Min.   :27.82   Min.   :-17.8889   Min.   :   1.0  
 1st Qu.: 0.00000   1st Qu.:37.28   1st Qu.: -5.8792   1st Qu.:  32.0  
 Median : 0.00000   Median :40.38   Median : -3.6781   Median :  90.0  
 Mean   : 0.00711   Mean   :38.96   Mean   : -3.9624   Mean   : 296.7  
 3rd Qu.: 0.00000   3rd Qu.:41.77   3rd Qu.:  0.3664   3rd Qu.: 540.0  
 Max.   :35.00000   Max.   :43.57   Max.   :  4.2156   Max.   :2535.0  
if (!empty_nodes) summary(df.cluster04)
   fecha_cnt          tmax             tmin            precip           nevada 
 Min.   :1.000   Min.   :-12.00   Min.   :-72.00   Min.   : 16.00   Min.   :0  
 1st Qu.:2.000   1st Qu.: 10.00   1st Qu.:-44.00   1st Qu.: 36.00   1st Qu.:0  
 Median :2.000   Median : 15.00   Median :-34.00   Median : 52.00   Median :0  
 Mean   :2.333   Mean   : 24.19   Mean   :-31.95   Mean   : 61.29   Mean   :0  
 3rd Qu.:3.000   3rd Qu.: 29.00   3rd Qu.:-24.00   3rd Qu.: 78.00   3rd Qu.:0  
 Max.   :4.000   Max.   : 76.00   Max.   :  8.00   Max.   :180.00   Max.   :0  
   prof_nieve       longitud        latitud         altitud    
 Min.   :415.0   Min.   :40.78   Min.   :-4.01   Min.   :1894  
 1st Qu.:503.0   1st Qu.:40.78   1st Qu.:-4.01   1st Qu.:1894  
 Median :592.0   Median :40.78   Median :-4.01   Median :1894  
 Mean   :594.6   Mean   :40.78   Mean   :-4.01   Mean   :1894  
 3rd Qu.:657.0   3rd Qu.:40.78   3rd Qu.:-4.01   3rd Qu.:1894  
 Max.   :892.0   Max.   :40.78   Max.   :-4.01   Max.   :1894  
if (!empty_nodes) summary(df.cluster05)
   fecha_cnt           tmax            tmin             precip      
 Min.   : 1.000   Min.   :-53.0   Min.   :-121.00   Min.   :  0.00  
 1st Qu.: 2.000   1st Qu.:110.0   1st Qu.:  17.00   1st Qu.:  4.00  
 Median : 3.000   Median :143.0   Median :  43.00   Median : 10.00  
 Mean   : 5.522   Mean   :137.7   Mean   :  39.74   Mean   : 12.95  
 3rd Qu.:11.000   3rd Qu.:169.0   3rd Qu.:  66.00   3rd Qu.: 19.00  
 Max.   :12.000   Max.   :250.0   Max.   : 157.00   Max.   :106.00  
     nevada    prof_nieve          longitud        latitud       
 Min.   :0   Min.   :  0.0000   Min.   :28.31   Min.   :-17.755  
 1st Qu.:0   1st Qu.:  0.0000   1st Qu.:39.85   1st Qu.: -4.680  
 Median :0   Median :  0.0000   Median :41.10   Median : -2.357  
 Mean   :0   Mean   :  0.2286   Mean   :40.45   Mean   : -2.526  
 3rd Qu.:0   3rd Qu.:  0.0000   3rd Qu.:42.08   3rd Qu.:  0.595  
 Max.   :0   Max.   :104.0000   Max.   :43.57   Max.   :  4.216  
    altitud      
 Min.   :   1.0  
 1st Qu.:  90.0  
 Median : 540.0  
 Mean   : 603.5  
 3rd Qu.: 846.0  
 Max.   :2535.0  
if (!empty_nodes) summary(df.cluster06)
   fecha_cnt      tmax            tmin        precip          nevada   
 Min.   :2   Min.   :71.00   Min.   :-1   Min.   :14.00   Min.   :4.0  
 1st Qu.:2   1st Qu.:72.25   1st Qu.:-1   1st Qu.:15.25   1st Qu.:4.5  
 Median :2   Median :73.50   Median :-1   Median :16.50   Median :5.0  
 Mean   :2   Mean   :73.50   Mean   :-1   Mean   :16.50   Mean   :5.0  
 3rd Qu.:2   3rd Qu.:74.75   3rd Qu.:-1   3rd Qu.:17.75   3rd Qu.:5.5  
 Max.   :2   Max.   :76.00   Max.   :-1   Max.   :19.00   Max.   :6.0  
   prof_nieve    longitud        latitud          altitud     
 Min.   : 5   Min.   :40.48   Min.   :-3.450   Min.   :263.0  
 1st Qu.: 7   1st Qu.:40.78   1st Qu.:-2.846   1st Qu.:349.3  
 Median : 9   Median :41.08   Median :-2.242   Median :435.6  
 Mean   : 9   Mean   :41.08   Mean   :-2.242   Mean   :435.6  
 3rd Qu.:11   3rd Qu.:41.37   3rd Qu.:-1.637   3rd Qu.:521.8  
 Max.   :13   Max.   :41.67   Max.   :-1.033   Max.   :608.1  
if (!empty_nodes) summary(df.cluster07)
   fecha_cnt           tmax             tmin            precip      
 Min.   : 1.000   Min.   :-12.00   Min.   :-63.00   Min.   :  2.00  
 1st Qu.: 1.000   1st Qu.: 16.00   1st Qu.:-35.00   1st Qu.: 29.00  
 Median : 2.000   Median : 34.00   Median :-23.00   Median : 43.00  
 Mean   : 3.685   Mean   : 36.15   Mean   :-22.38   Mean   : 47.01  
 3rd Qu.: 4.000   3rd Qu.: 49.00   3rd Qu.: -8.00   3rd Qu.: 67.00  
 Max.   :12.000   Max.   : 99.00   Max.   : 28.00   Max.   :126.00  
     nevada    prof_nieve       longitud        latitud         altitud    
 Min.   :0   Min.   :106.0   Min.   :40.78   Min.   :-4.01   Min.   :1894  
 1st Qu.:0   1st Qu.:144.0   1st Qu.:40.78   1st Qu.:-4.01   1st Qu.:1894  
 Median :0   Median :197.0   Median :40.78   Median :-4.01   Median :1894  
 Mean   :0   Mean   :209.1   Mean   :40.78   Mean   :-4.01   Mean   :1894  
 3rd Qu.:0   3rd Qu.:259.0   3rd Qu.:40.78   3rd Qu.:-4.01   3rd Qu.:1894  
 Max.   :0   Max.   :390.0   Max.   :40.78   Max.   :-4.01   Max.   :1894  
if (!empty_nodes) summary(df.cluster08)
   fecha_cnt           tmax            tmin            precip     
 Min.   : 1.000   Min.   : 69.0   Min.   :-15.00   Min.   : 3.00  
 1st Qu.: 2.000   1st Qu.: 89.0   1st Qu.: -5.00   1st Qu.: 7.50  
 Median : 2.000   Median : 96.0   Median : 27.00   Median :12.00  
 Mean   : 6.143   Mean   :100.4   Mean   : 14.29   Mean   :11.86  
 3rd Qu.:12.000   3rd Qu.:110.0   3rd Qu.: 31.50   3rd Qu.:14.50  
 Max.   :12.000   Max.   :140.0   Max.   : 35.00   Max.   :24.00  
     nevada        prof_nieve       longitud        latitud      
 Min.   :2.000   Min.   :0.000   Min.   :40.48   Min.   :-3.450  
 1st Qu.:2.000   1st Qu.:0.000   1st Qu.:40.48   1st Qu.:-3.450  
 Median :2.000   Median :1.000   Median :41.67   Median :-1.033  
 Mean   :2.143   Mean   :1.429   Mean   :41.16   Mean   :-2.069  
 3rd Qu.:2.000   3rd Qu.:1.000   3rd Qu.:41.67   3rd Qu.:-1.033  
 Max.   :3.000   Max.   :7.000   Max.   :41.67   Max.   :-1.033  
    altitud     
 Min.   :263.0  
 1st Qu.:263.0  
 Median :263.0  
 Mean   :410.9  
 3rd Qu.:608.1  
 Max.   :608.1  
if (!empty_nodes) summary(df.cluster09)
   fecha_cnt        tmax           tmin           precip         nevada 
 Min.   :2.0   Min.   :-4.0   Min.   :-51.0   Min.   :19.0   Min.   :0  
 1st Qu.:2.0   1st Qu.: 0.0   1st Qu.:-48.0   1st Qu.:33.0   1st Qu.:0  
 Median :3.0   Median :35.0   Median :-26.0   Median :49.0   Median :0  
 Mean   :2.6   Mean   :20.6   Mean   :-32.8   Mean   :41.4   Mean   :0  
 3rd Qu.:3.0   3rd Qu.:36.0   3rd Qu.:-23.0   3rd Qu.:50.0   3rd Qu.:0  
 Max.   :3.0   Max.   :36.0   Max.   :-16.0   Max.   :56.0   Max.   :0  
   prof_nieve      longitud        latitud         altitud    
 Min.   :1017   Min.   :40.78   Min.   :-4.01   Min.   :1894  
 1st Qu.:1073   1st Qu.:40.78   1st Qu.:-4.01   1st Qu.:1894  
 Median :1168   Median :40.78   Median :-4.01   Median :1894  
 Mean   :1317   Mean   :40.78   Mean   :-4.01   Mean   :1894  
 3rd Qu.:1494   3rd Qu.:40.78   3rd Qu.:-4.01   3rd Qu.:1894  
 Max.   :1834   Max.   :40.78   Max.   :-4.01   Max.   :1894  
if (!empty_nodes) summary(df.cluster10)
   fecha_cnt           tmax            tmin           precip          nevada 
 Min.   : 1.000   Min.   :86.00   Min.   :-24.0   Min.   : 6.00   Min.   :1  
 1st Qu.: 6.500   1st Qu.:86.00   1st Qu.:-19.5   1st Qu.: 6.00   1st Qu.:1  
 Median :12.000   Median :86.00   Median :-15.0   Median : 6.00   Median :1  
 Mean   : 8.333   Mean   :88.33   Mean   : -7.0   Mean   :10.33   Mean   :1  
 3rd Qu.:12.000   3rd Qu.:89.50   3rd Qu.:  1.5   3rd Qu.:12.50   3rd Qu.:1  
 Max.   :12.000   Max.   :93.00   Max.   : 18.0   Max.   :19.00   Max.   :1  
   prof_nieve        longitud        latitud          altitud     
 Min.   :0.0000   Min.   :40.48   Min.   :-3.450   Min.   :263.0  
 1st Qu.:0.0000   1st Qu.:40.48   1st Qu.:-3.450   1st Qu.:435.6  
 Median :0.0000   Median :40.48   Median :-3.450   Median :608.1  
 Mean   :0.3333   Mean   :40.88   Mean   :-2.644   Mean   :493.1  
 3rd Qu.:0.5000   3rd Qu.:41.08   3rd Qu.:-2.242   3rd Qu.:608.1  
 Max.   :1.0000   Max.   :41.67   Max.   :-1.033   Max.   :608.1  

NĂºmero de elementos en cada clĂºster

if (!empty_nodes) {
  df.clusters.dim <- c(dim(df.cluster01)[1], dim(df.cluster02)[1], dim(df.cluster03)[1], dim(df.cluster04)[1], dim(df.cluster05)[1], dim(df.cluster06)[1], dim(df.cluster07)[1], dim(df.cluster08)[1], dim(df.cluster09)[1], dim(df.cluster10)[1])
  barplot(df.clusters.dim,
          names.arg = c("cluster01", "cluster02", "cluster03", "cluster04", "cluster05", "cluster06", "cluster07", "cluster08", "cluster09", "cluster10"),
          col = "steelblue1")
}

DistribuciĂ³n de los datos

if (!empty_nodes) mpr.hist(df.cluster01)

if (!empty_nodes) mpr.hist(df.cluster02)

if (!empty_nodes) mpr.hist(df.cluster03)

if (!empty_nodes) mpr.hist(df.cluster04)

if (!empty_nodes) mpr.hist(df.cluster05)

if (!empty_nodes) mpr.hist(df.cluster06)

if (!empty_nodes) mpr.hist(df.cluster07)

if (!empty_nodes) mpr.hist(df.cluster08)

if (!empty_nodes) mpr.hist(df.cluster09)

if (!empty_nodes) mpr.hist(df.cluster10)

if (!empty_nodes) mpr.boxplot(df.cluster01)
if (!empty_nodes) mpr.boxplot(df.cluster02)

if (!empty_nodes) mpr.boxplot(df.cluster03)

if (!empty_nodes) mpr.boxplot(df.cluster04)

if (!empty_nodes) mpr.boxplot(df.cluster05)

if (!empty_nodes) mpr.boxplot(df.cluster06)

if (!empty_nodes) mpr.boxplot(df.cluster07)

if (!empty_nodes) mpr.boxplot(df.cluster08)

if (!empty_nodes) mpr.boxplot(df.cluster09)

if (!empty_nodes) mpr.boxplot(df.cluster10)

LocalizaciĂ³n geogrĂ¡fica de las estaciones de medida de cada cluster

# Agrupa por longitud y latitud para rellenar el mapa con menos datos.
if (!empty_nodes) {
  df.cluster01.grouped <- mpr.group_by_geo(df.cluster01)
  df.cluster02.grouped <- mpr.group_by_geo(df.cluster02)
  df.cluster03.grouped <- mpr.group_by_geo(df.cluster03)
  df.cluster04.grouped <- mpr.group_by_geo(df.cluster04)
  df.cluster05.grouped <- mpr.group_by_geo(df.cluster05)
  df.cluster06.grouped <- mpr.group_by_geo(df.cluster06)
  df.cluster07.grouped <- mpr.group_by_geo(df.cluster07)
  df.cluster08.grouped <- mpr.group_by_geo(df.cluster08)
  df.cluster09.grouped <- mpr.group_by_geo(df.cluster09)
  df.cluster10.grouped <- mpr.group_by_geo(df.cluster10)
}
if (!empty_nodes) mpr.draw_map(spain, df.cluster01.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster02.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster03.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster04.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster05.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster06.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster07.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster08.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster09.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster10.grouped)

LS0tCnRpdGxlOiAiQW7DoWxpc2lzIGRlIG1vZGVsb3MgU09NIC0gRnJlY3VlbmNpYSBkYXRvcyBkZSBlbnRyYWRhOiBtZXMiCm91dHB1dDogaHRtbF9ub3RlYm9vawotLS0KCiMgTW9kZWxvCgoqIElEOiAzNTMKKiBEZXNjcmlwY2nDs246IAoqIEZyZWN1ZW5jaWE6IG1lcwoqIFZhcmlhYmxlczogdG1heCwgdG1pbiwgcHJlY2lwLCBuZXZhZGEsIHByb2ZfbmlldmUKKiBEaW1lbnNpb25lcyBkZWwgbWFwYTogNSw1CiogSXRlcmFjaW9uZXM6IDEwMDAKKiBQYXLDoW1ldHJvcyBhZGljaW9uYWxlczogCgpgYGB7cn0Kc291cmNlKCIuLi8uLi9saWIvc29tLXV0aWxzLlIiKQpzb3VyY2UoIi4uLy4uL2xpYi9tYXBzLXV0aWxzLlIiKQpgYGAKCiMgQ2FyZ2EgZGVsIG1vZGVsbyBkZXNkZSBkaXNjbwoKYGBge3J9Cm1wci5zZXRfYmFzZV9wYXRoX2FuYWx5c2lzKCkKbW9kZWwgPC0gbXByLmxvYWRfbW9kZWwoInNvbS0zNTMucmRzLnh6IikKc3VtbWFyeShtb2RlbCkKYGBgCgpgYGB7cn0KcGxvdChtb2RlbCwgdHlwZT0iY2hhbmdlcyIpCmBgYAoKIyBDYXJnYSBkZWwgZGF0YXNldCBkZSBlbnRyYWRhCgpgYGB7cn0KZGYgPC0gbXByLmxvYWRfZGF0YSgiZGF0b3NfbWVzLmNzdi54eiIpCmBgYAoKYGBge3J9CmRmCmBgYAoKYGBge3J9CnN1bW1hcnkoZGYpCmBgYAoKIyBDYXJnYSBkZSBsb3MgbWFwYXMKCmBgYHtyfQp3b3JsZCA8LSBuZV9jb3VudHJpZXMoc2NhbGUgPSAibWVkaXVtIiwgcmV0dXJuY2xhc3MgPSAic2YiKQpzcGFpbiA8LSBzdWJzZXQod29ybGQsIGFkbWluID09ICJTcGFpbiIpCmBgYAoKIyBNYXBhIGRlIGRlbnNpZGFkCgpgYGB7cn0KcGxvdChtb2RlbCwgdHlwZT0iY291bnQiLCBzaGFwZSA9ICJzdHJhaWdodCIsIHBhbGV0dGUubmFtZSA9IG1wci5kZWdyYWRlLmJsZXUpCmBgYAoKTsO6bWVybyBkZSBlbGVtZW50b3MgZW4gY2FkYSBjZWxkYToKCmBgYHtyfQpuYiA8LSB0YWJsZShtb2RlbCR1bml0LmNsYXNzaWYpCnByaW50KG5iKQpgYGAKQ29tcHJvYmFjacOzbiBkZSBub2RvcyB2YWPDrW9zOgoKYGBge3J9CmRpbV9tb2RlbCA8LSA1KjU7Cmxlbl9uYiA9IGxlbmd0aChuYik7CmVtcHR5X25vZGVzIDwtIGRpbV9tb2RlbCAhPSBsZW5fbmI7CmlmIChlbXB0eV9ub2RlcykgewogIHByaW50KHBhc3RlKCJbV2FybmluZ10gRXhpc3RlbiBub2RvcyB2YWPDrW9zOiAiLCBsZW5fbmIsICIvIiwgZGltX21vZGVsKSkKfQpgYGAKCiMgTWFwYSBkZSBkaXN0YW5jaWEgZW50cmUgdmVjaW5vcwoKYGBge3J9CnBsb3QobW9kZWwsIHR5cGU9ImRpc3QubmVpZ2hib3VycyIsIHNoYXBlID0gInN0cmFpZ2h0IikKYGBgCgojIEluZmx1ZW5jaWEgZGUgbGFzIHZhcmlhYmxlcwoKYGBge3J9Cm1vZGVsX2NvbG5hbWVzID0gYygidG1heCIsICJ0bWluIiwgInByZWNpcCIsICJuZXZhZGEiLCAicHJvZl9uaWV2ZSIpCm1vZGVsX25jb2wgPSBsZW5ndGgobW9kZWxfY29sbmFtZXMpCmBgYAoKIyMgTWFwYSBkZSB2YXJpYWJsZXMuCgpgYGB7cn0KcGxvdChtb2RlbCwgc2hhcGUgPSAic3RyYWlnaHQiKQpgYGAKCiMjIE1hcGEgZGUgY2Fsb3IgcG9yIHZhcmlhYmxlCgpgYGB7cn0KcGFyKG1mcm93PWMoMyw0KSkKZm9yIChqIGluIDE6bW9kZWxfbmNvbCkgewogIHBsb3QobW9kZWwsIHR5cGU9InByb3BlcnR5IiwgcHJvcGVydHk9Z2V0Q29kZXMobW9kZWwsMSlbLGpdLAogICAgcGFsZXR0ZS5uYW1lPW1wci5jb29sQmx1ZUhvdFJlZCwKICAgIG1haW49bW9kZWxfY29sbmFtZXNbal0sCiAgICBjZXg9MC41LCBzaGFwZSA9ICJzdHJhaWdodCIpCn0KYGBgCgojIyBDb3JyZWxhY2nDs24gcGFyYSBjYWRhIGNvbHVtbmEgZGVsIHZlY3RvciBkZSBub2RvcwoKYGBge3J9CmlmICghZW1wdHlfbm9kZXMpIHsKICBjb3IgPC0gYXBwbHkoZ2V0Q29kZXMobW9kZWwsMSksIDIsIG1wci53ZWlnaHRlZC5jb3JyZWxhdGlvbiwgdz1uYiwgc29tPW1vZGVsKQogIHByaW50KGNvcikKfQpgYGAKClJlcHJlc2VudGFjacOzbiBkZSBjYWRhIHZhcmlhYmxlIGVuIHVuIG1hcGEgZGUgZmFjdG9yZXM6CgpgYGB7cn0KaWYgKCFlbXB0eV9ub2RlcykgewogIHBhcihtZnJvdz1jKDEsMSkpCiAgcGxvdChjb3JbMSxdLCBjb3JbMixdLCB4bGltPWMoLTEsMSksIHlsaW09YygtMSwxKSwgdHlwZT0ibiIpCiAgbGluZXMoYygtMSwxKSxjKDAsMCkpCiAgbGluZXMoYygwLDApLGMoLTEsMSkpCiAgdGV4dChjb3JbMSxdLCBjb3JbMixdLCBsYWJlbHM9bW9kZWxfY29sbmFtZXMsIGNleD0wLjc1KQogIHN5bWJvbHMoMCwwLGNpcmNsZXM9MSxpbmNoZXM9RixhZGQ9VCkKfQpgYGAKCkltcG9ydGFuY2lhIGRlIGNhZGEgdmFyaWFibGUgLSB2YXJpYW56YSBwb25kZXJhZGEgcG9yIGVsIHRhbWHDsW8gZGUgbGEgY2VsZGE6CgpgYGB7cn0KaWYgKCFlbXB0eV9ub2RlcykgewogIHNpZ21hMiA8LSBzcXJ0KGFwcGx5KGdldENvZGVzKG1vZGVsLDEpLDIsZnVuY3Rpb24oeCxlZmZlY3RpZikKICAgICB7bTwtc3VtKGVmZmVjdGlmKih4LXdlaWdodGVkLm1lYW4oeCxlZmZlY3RpZikpXjIpLyhzdW0oZWZmZWN0aWYpLTEpfSwKICAgICBlZmZlY3RpZj1uYikpCiAgcHJpbnQoc29ydChzaWdtYTIsZGVjcmVhc2luZz1UKSkKfQpgYGAKCiMgQ2x1c3RlcmluZwoKYGBge3J9CmlmICghZW1wdHlfbm9kZXMpIHsKICBoYWMgPC0gbXByLmhhYyhtb2RlbCwgbmIpCn0KYGBgCgojIyBWaXN1YWxpemFjacOzbiBkZSAzIGNsw7pzdGVyZXM6CgpgYGB7cn0KaWYgKCFlbXB0eV9ub2RlcykgewogIHBsb3QoaGFjLCBoYW5nPS0xLCBsYWJlbHM9RikKICByZWN0LmhjbHVzdChoYWMsIGs9MykKfQpgYGAKCiMjIyBWaXN1YWxpemFjacOzbiBkZSBsb3MgY2zDunN0ZXJzIGVuIGVsIG1hcGEKCkEgcXXDqSBjbMO6c3RlciBwZXJ0ZW5lY2UgY2FkYSBub2RvIGRlbCBtYXBhIGRlIGtvaG9uZW46CgpgYGB7cn0KaWYgKCFlbXB0eV9ub2RlcykgewogIGdyb3VwcyA8LSBjdXRyZWUoaGFjLCBrPTMpCiAgcGxvdChtb2RlbCwgdHlwZT0ibWFwcGluZyIsCiAgICBiZ2NvbD1jKCJzdGVlbGJsdWUxIiwic2llbm5hMSIsInllbGxvd2dyZWVuIiwicmVkIiwiYmx1ZSIsInllbGxvdyIsInB1cnBsZSIsImdyZWVuIiwid2hpdGUiLCIjMWY3N2I0IiwgJyNmZjdmMGUnLCAnIzJjYTAyYycsICcjZDYyNzI4JywgJyM5NDY3YmQnLCAnIzhjNTY0YicsICcjZTM3N2MyJylbZ3JvdXBzXSwKICAgIHNoYXBlID0gInN0cmFpZ2h0IiwgbGFiZWxzID0gIiIpCiAgYWRkLmNsdXN0ZXIuYm91bmRhcmllcyhtb2RlbCwgY2x1c3RlcmluZz1ncm91cHMpCn0KYGBgCgojIyMgQW7DoWxpc2lzIGRlIGxhcyBvYnNlcnZhY2lvbmVzIGRlIGNhZGEgY2x1c3RlcgoKYGBge3J9CmlmICghZW1wdHlfbm9kZXMpIHsKICAjIEFzaWduYW1vcyBhIGNhZGEgcmVnaXN0cm8gc3UgY2zDunN0ZXIKICBkZiRjbHVzdGVyIDwtIGdyb3Vwc1ttb2RlbCR1bml0LmNsYXNzaWZdCn0KYGBgCgpOdWV2b3MgZGF0YWZyYW1lcyBwb3IgY2x1c3RlcgoKYGBge3J9CmlmICghZW1wdHlfbm9kZXMpIHsKICAjIENyZW8gbnVldm9zIGRhdGFmcmFtZXMsIHVubyBwb3IgY2FkYSBjbMO6c3Rlci4KICBkZi5jbHVzdGVyMDEgPC0gc3Vic2V0KGRmLCBjbHVzdGVyPT0xKQogIGRmLmNsdXN0ZXIwMiA8LSBzdWJzZXQoZGYsIGNsdXN0ZXI9PTIpCiAgZGYuY2x1c3RlcjAzIDwtIHN1YnNldChkZiwgY2x1c3Rlcj09MykKCiAgIyBFeHRyYWlnbyBkZWwgZGF0YWZyYW1lIGxhcyBmZWF0dXJlcy4KICBkZi5jbHVzdGVyMDEgPC0gc2VsZWN0KGRmLmNsdXN0ZXIwMSwgZmVjaGFfY250LCB0bWF4LCB0bWluLCBwcmVjaXAsIG5ldmFkYSwgcHJvZl9uaWV2ZSwgbG9uZ2l0dWQsIGxhdGl0dWQsIGFsdGl0dWQpCiAgZGYuY2x1c3RlcjAyIDwtIHNlbGVjdChkZi5jbHVzdGVyMDIsIGZlY2hhX2NudCwgdG1heCwgdG1pbiwgcHJlY2lwLCBuZXZhZGEsIHByb2ZfbmlldmUsIGxvbmdpdHVkLCBsYXRpdHVkLCBhbHRpdHVkKQogIGRmLmNsdXN0ZXIwMyA8LSBzZWxlY3QoZGYuY2x1c3RlcjAzLCBmZWNoYV9jbnQsIHRtYXgsIHRtaW4sIHByZWNpcCwgbmV2YWRhLCBwcm9mX25pZXZlLCBsb25naXR1ZCwgbGF0aXR1ZCwgYWx0aXR1ZCkKfQpgYGAKCmBgYHtyfQppZiAoIWVtcHR5X25vZGVzKSBzdW1tYXJ5KGRmLmNsdXN0ZXIwMSkKaWYgKCFlbXB0eV9ub2Rlcykgc3VtbWFyeShkZi5jbHVzdGVyMDIpCmlmICghZW1wdHlfbm9kZXMpIHN1bW1hcnkoZGYuY2x1c3RlcjAzKQpgYGAKCiMjIyMgTsO6bWVybyBkZSBlbGVtZW50b3MgZW4gY2FkYSBjbMO6c3RlcgoKYGBge3J9CmlmICghZW1wdHlfbm9kZXMpIHsKICBkZi5jbHVzdGVycy5kaW0gPC0gYyhkaW0oZGYuY2x1c3RlcjAxKVsxXSwgZGltKGRmLmNsdXN0ZXIwMilbMV0sIGRpbShkZi5jbHVzdGVyMDMpWzFdKQogIGJhcnBsb3QoZGYuY2x1c3RlcnMuZGltLAogICAgICAgICAgbmFtZXMuYXJnID0gYygiY2x1c3RlcjAxIiwgImNsdXN0ZXIwMiIsICJjbHVzdGVyMDMiKSwKICAgICAgICAgIGNvbCA9ICJzdGVlbGJsdWUxIikKfQpgYGAKCiMjIyMgRGlzdHJpYnVjacOzbiBkZSBsb3MgZGF0b3MKCmBgYHtyIGZpZy5oZWlnaHQ9N30KaWYgKCFlbXB0eV9ub2RlcykgbXByLmhpc3QoZGYuY2x1c3RlcjAxKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuaGlzdChkZi5jbHVzdGVyMDIpCmlmICghZW1wdHlfbm9kZXMpIG1wci5oaXN0KGRmLmNsdXN0ZXIwMykKYGBgCgpgYGB7ciBmaWcuaGVpZ2h0PTV9CmlmICghZW1wdHlfbm9kZXMpIG1wci5ib3hwbG90KGRmLmNsdXN0ZXIwMSkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmJveHBsb3QoZGYuY2x1c3RlcjAyKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuYm94cGxvdChkZi5jbHVzdGVyMDMpCmBgYAoKIyMjIExvY2FsaXphY2nDs24gZ2VvZ3LDoWZpY2EgZGUgbGFzIGVzdGFjaW9uZXMgZGUgbWVkaWRhIGRlIGNhZGEgY2x1c3RlcgoKYGBge3J9CiMgQWdydXBhIHBvciBsb25naXR1ZCB5IGxhdGl0dWQgcGFyYSByZWxsZW5hciBlbCBtYXBhIGNvbiBtZW5vcyBkYXRvcy4KaWYgKCFlbXB0eV9ub2RlcykgewogIGRmLmNsdXN0ZXIwMS5ncm91cGVkIDwtIG1wci5ncm91cF9ieV9nZW8oZGYuY2x1c3RlcjAxKQogIGRmLmNsdXN0ZXIwMi5ncm91cGVkIDwtIG1wci5ncm91cF9ieV9nZW8oZGYuY2x1c3RlcjAyKQogIGRmLmNsdXN0ZXIwMy5ncm91cGVkIDwtIG1wci5ncm91cF9ieV9nZW8oZGYuY2x1c3RlcjAzKQp9CmBgYAoKYGBge3J9CmlmICghZW1wdHlfbm9kZXMpIG1wci5kcmF3X21hcChzcGFpbiwgZGYuY2x1c3RlcjAxLmdyb3VwZWQpCmlmICghZW1wdHlfbm9kZXMpIG1wci5kcmF3X21hcChzcGFpbiwgZGYuY2x1c3RlcjAyLmdyb3VwZWQpCmlmICghZW1wdHlfbm9kZXMpIG1wci5kcmF3X21hcChzcGFpbiwgZGYuY2x1c3RlcjAzLmdyb3VwZWQpCmBgYAoKIyMgVmlzdWFsaXphY2nDs24gZGUgNCBjbMO6c3RlcmVzOgoKYGBge3J9CmlmICghZW1wdHlfbm9kZXMpIHsKICBwbG90KGhhYywgaGFuZz0tMSwgbGFiZWxzPUYpCiAgcmVjdC5oY2x1c3QoaGFjLCBrPTQpCn0KYGBgCgojIyMgVmlzdWFsaXphY2nDs24gZGUgbG9zIGNsw7pzdGVycyBlbiBlbCBtYXBhCgpBIHF1w6kgY2zDunN0ZXIgcGVydGVuZWNlIGNhZGEgbm9kbyBkZWwgbWFwYSBkZSBrb2hvbmVuOgoKYGBge3J9CmlmICghZW1wdHlfbm9kZXMpIHsKICBncm91cHMgPC0gY3V0cmVlKGhhYywgaz00KQogIHBsb3QobW9kZWwsIHR5cGU9Im1hcHBpbmciLAogICAgYmdjb2w9Yygic3RlZWxibHVlMSIsInNpZW5uYTEiLCJ5ZWxsb3dncmVlbiIsInJlZCIsImJsdWUiLCJ5ZWxsb3ciLCJwdXJwbGUiLCJncmVlbiIsIndoaXRlIiwiIzFmNzdiNCIsICcjZmY3ZjBlJywgJyMyY2EwMmMnLCAnI2Q2MjcyOCcsICcjOTQ2N2JkJywgJyM4YzU2NGInLCAnI2UzNzdjMicpW2dyb3Vwc10sCiAgICBzaGFwZSA9ICJzdHJhaWdodCIsIGxhYmVscyA9ICIiKQogIGFkZC5jbHVzdGVyLmJvdW5kYXJpZXMobW9kZWwsIGNsdXN0ZXJpbmc9Z3JvdXBzKQp9CmBgYAoKIyMjIEFuw6FsaXNpcyBkZSBsYXMgb2JzZXJ2YWNpb25lcyBkZSBjYWRhIGNsdXN0ZXIKCmBgYHtyfQppZiAoIWVtcHR5X25vZGVzKSB7CiAgIyBBc2lnbmFtb3MgYSBjYWRhIHJlZ2lzdHJvIHN1IGNsw7pzdGVyCiAgZGYkY2x1c3RlciA8LSBncm91cHNbbW9kZWwkdW5pdC5jbGFzc2lmXQp9CmBgYAoKTnVldm9zIGRhdGFmcmFtZXMgcG9yIGNsdXN0ZXIKCmBgYHtyfQppZiAoIWVtcHR5X25vZGVzKSB7CiAgIyBDcmVvIG51ZXZvcyBkYXRhZnJhbWVzLCB1bm8gcG9yIGNhZGEgY2zDunN0ZXIuCiAgZGYuY2x1c3RlcjAxIDwtIHN1YnNldChkZiwgY2x1c3Rlcj09MSkKICBkZi5jbHVzdGVyMDIgPC0gc3Vic2V0KGRmLCBjbHVzdGVyPT0yKQogIGRmLmNsdXN0ZXIwMyA8LSBzdWJzZXQoZGYsIGNsdXN0ZXI9PTMpCiAgZGYuY2x1c3RlcjA0IDwtIHN1YnNldChkZiwgY2x1c3Rlcj09NCkKCiAgIyBFeHRyYWlnbyBkZWwgZGF0YWZyYW1lIGxhcyBmZWF0dXJlcy4KICBkZi5jbHVzdGVyMDEgPC0gc2VsZWN0KGRmLmNsdXN0ZXIwMSwgZmVjaGFfY250LCB0bWF4LCB0bWluLCBwcmVjaXAsIG5ldmFkYSwgcHJvZl9uaWV2ZSwgbG9uZ2l0dWQsIGxhdGl0dWQsIGFsdGl0dWQpCiAgZGYuY2x1c3RlcjAyIDwtIHNlbGVjdChkZi5jbHVzdGVyMDIsIGZlY2hhX2NudCwgdG1heCwgdG1pbiwgcHJlY2lwLCBuZXZhZGEsIHByb2ZfbmlldmUsIGxvbmdpdHVkLCBsYXRpdHVkLCBhbHRpdHVkKQogIGRmLmNsdXN0ZXIwMyA8LSBzZWxlY3QoZGYuY2x1c3RlcjAzLCBmZWNoYV9jbnQsIHRtYXgsIHRtaW4sIHByZWNpcCwgbmV2YWRhLCBwcm9mX25pZXZlLCBsb25naXR1ZCwgbGF0aXR1ZCwgYWx0aXR1ZCkKICBkZi5jbHVzdGVyMDQgPC0gc2VsZWN0KGRmLmNsdXN0ZXIwNCwgZmVjaGFfY250LCB0bWF4LCB0bWluLCBwcmVjaXAsIG5ldmFkYSwgcHJvZl9uaWV2ZSwgbG9uZ2l0dWQsIGxhdGl0dWQsIGFsdGl0dWQpCn0KYGBgCgpgYGB7cn0KaWYgKCFlbXB0eV9ub2Rlcykgc3VtbWFyeShkZi5jbHVzdGVyMDEpCmlmICghZW1wdHlfbm9kZXMpIHN1bW1hcnkoZGYuY2x1c3RlcjAyKQppZiAoIWVtcHR5X25vZGVzKSBzdW1tYXJ5KGRmLmNsdXN0ZXIwMykKaWYgKCFlbXB0eV9ub2Rlcykgc3VtbWFyeShkZi5jbHVzdGVyMDQpCmBgYAoKIyMjIyBOw7ptZXJvIGRlIGVsZW1lbnRvcyBlbiBjYWRhIGNsw7pzdGVyCgpgYGB7cn0KaWYgKCFlbXB0eV9ub2RlcykgewogIGRmLmNsdXN0ZXJzLmRpbSA8LSBjKGRpbShkZi5jbHVzdGVyMDEpWzFdLCBkaW0oZGYuY2x1c3RlcjAyKVsxXSwgZGltKGRmLmNsdXN0ZXIwMylbMV0sIGRpbShkZi5jbHVzdGVyMDQpWzFdKQogIGJhcnBsb3QoZGYuY2x1c3RlcnMuZGltLAogICAgICAgICAgbmFtZXMuYXJnID0gYygiY2x1c3RlcjAxIiwgImNsdXN0ZXIwMiIsICJjbHVzdGVyMDMiLCAiY2x1c3RlcjA0IiksCiAgICAgICAgICBjb2wgPSAic3RlZWxibHVlMSIpCn0KYGBgCgojIyMjIERpc3RyaWJ1Y2nDs24gZGUgbG9zIGRhdG9zCgpgYGB7ciBmaWcuaGVpZ2h0PTd9CmlmICghZW1wdHlfbm9kZXMpIG1wci5oaXN0KGRmLmNsdXN0ZXIwMSkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmhpc3QoZGYuY2x1c3RlcjAyKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuaGlzdChkZi5jbHVzdGVyMDMpCmlmICghZW1wdHlfbm9kZXMpIG1wci5oaXN0KGRmLmNsdXN0ZXIwNCkKYGBgCgpgYGB7ciBmaWcuaGVpZ2h0PTV9CmlmICghZW1wdHlfbm9kZXMpIG1wci5ib3hwbG90KGRmLmNsdXN0ZXIwMSkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmJveHBsb3QoZGYuY2x1c3RlcjAyKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuYm94cGxvdChkZi5jbHVzdGVyMDMpCmlmICghZW1wdHlfbm9kZXMpIG1wci5ib3hwbG90KGRmLmNsdXN0ZXIwNCkKYGBgCgojIyMgTG9jYWxpemFjacOzbiBnZW9ncsOhZmljYSBkZSBsYXMgZXN0YWNpb25lcyBkZSBtZWRpZGEgZGUgY2FkYSBjbHVzdGVyCgpgYGB7cn0KIyBBZ3J1cGEgcG9yIGxvbmdpdHVkIHkgbGF0aXR1ZCBwYXJhIHJlbGxlbmFyIGVsIG1hcGEgY29uIG1lbm9zIGRhdG9zLgppZiAoIWVtcHR5X25vZGVzKSB7CiAgZGYuY2x1c3RlcjAxLmdyb3VwZWQgPC0gbXByLmdyb3VwX2J5X2dlbyhkZi5jbHVzdGVyMDEpCiAgZGYuY2x1c3RlcjAyLmdyb3VwZWQgPC0gbXByLmdyb3VwX2J5X2dlbyhkZi5jbHVzdGVyMDIpCiAgZGYuY2x1c3RlcjAzLmdyb3VwZWQgPC0gbXByLmdyb3VwX2J5X2dlbyhkZi5jbHVzdGVyMDMpCiAgZGYuY2x1c3RlcjA0Lmdyb3VwZWQgPC0gbXByLmdyb3VwX2J5X2dlbyhkZi5jbHVzdGVyMDQpCn0KYGBgCgpgYGB7cn0KaWYgKCFlbXB0eV9ub2RlcykgbXByLmRyYXdfbWFwKHNwYWluLCBkZi5jbHVzdGVyMDEuZ3JvdXBlZCkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmRyYXdfbWFwKHNwYWluLCBkZi5jbHVzdGVyMDIuZ3JvdXBlZCkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmRyYXdfbWFwKHNwYWluLCBkZi5jbHVzdGVyMDMuZ3JvdXBlZCkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmRyYXdfbWFwKHNwYWluLCBkZi5jbHVzdGVyMDQuZ3JvdXBlZCkKYGBgCgojIyBWaXN1YWxpemFjacOzbiBkZSA1IGNsw7pzdGVyZXM6CgpgYGB7cn0KaWYgKCFlbXB0eV9ub2RlcykgewogIHBsb3QoaGFjLCBoYW5nPS0xLCBsYWJlbHM9RikKICByZWN0LmhjbHVzdChoYWMsIGs9NSkKfQpgYGAKCiMjIyBWaXN1YWxpemFjacOzbiBkZSBsb3MgY2zDunN0ZXJzIGVuIGVsIG1hcGEKCkEgcXXDqSBjbMO6c3RlciBwZXJ0ZW5lY2UgY2FkYSBub2RvIGRlbCBtYXBhIGRlIGtvaG9uZW46CgpgYGB7cn0KaWYgKCFlbXB0eV9ub2RlcykgewogIGdyb3VwcyA8LSBjdXRyZWUoaGFjLCBrPTUpCiAgcGxvdChtb2RlbCwgdHlwZT0ibWFwcGluZyIsCiAgICBiZ2NvbD1jKCJzdGVlbGJsdWUxIiwic2llbm5hMSIsInllbGxvd2dyZWVuIiwicmVkIiwiYmx1ZSIsInllbGxvdyIsInB1cnBsZSIsImdyZWVuIiwid2hpdGUiLCIjMWY3N2I0IiwgJyNmZjdmMGUnLCAnIzJjYTAyYycsICcjZDYyNzI4JywgJyM5NDY3YmQnLCAnIzhjNTY0YicsICcjZTM3N2MyJylbZ3JvdXBzXSwKICAgIHNoYXBlID0gInN0cmFpZ2h0IiwgbGFiZWxzID0gIiIpCiAgYWRkLmNsdXN0ZXIuYm91bmRhcmllcyhtb2RlbCwgY2x1c3RlcmluZz1ncm91cHMpCn0KYGBgCgojIyMgQW7DoWxpc2lzIGRlIGxhcyBvYnNlcnZhY2lvbmVzIGRlIGNhZGEgY2x1c3RlcgoKYGBge3J9CmlmICghZW1wdHlfbm9kZXMpIHsKICAjIEFzaWduYW1vcyBhIGNhZGEgcmVnaXN0cm8gc3UgY2zDunN0ZXIKICBkZiRjbHVzdGVyIDwtIGdyb3Vwc1ttb2RlbCR1bml0LmNsYXNzaWZdCn0KYGBgCgpOdWV2b3MgZGF0YWZyYW1lcyBwb3IgY2x1c3RlcgoKYGBge3J9CmlmICghZW1wdHlfbm9kZXMpIHsKICAjIENyZW8gbnVldm9zIGRhdGFmcmFtZXMsIHVubyBwb3IgY2FkYSBjbMO6c3Rlci4KICBkZi5jbHVzdGVyMDEgPC0gc3Vic2V0KGRmLCBjbHVzdGVyPT0xKQogIGRmLmNsdXN0ZXIwMiA8LSBzdWJzZXQoZGYsIGNsdXN0ZXI9PTIpCiAgZGYuY2x1c3RlcjAzIDwtIHN1YnNldChkZiwgY2x1c3Rlcj09MykKICBkZi5jbHVzdGVyMDQgPC0gc3Vic2V0KGRmLCBjbHVzdGVyPT00KQogIGRmLmNsdXN0ZXIwNSA8LSBzdWJzZXQoZGYsIGNsdXN0ZXI9PTUpCgogICMgRXh0cmFpZ28gZGVsIGRhdGFmcmFtZSBsYXMgZmVhdHVyZXMuCiAgZGYuY2x1c3RlcjAxIDwtIHNlbGVjdChkZi5jbHVzdGVyMDEsIGZlY2hhX2NudCwgdG1heCwgdG1pbiwgcHJlY2lwLCBuZXZhZGEsIHByb2ZfbmlldmUsIGxvbmdpdHVkLCBsYXRpdHVkLCBhbHRpdHVkKQogIGRmLmNsdXN0ZXIwMiA8LSBzZWxlY3QoZGYuY2x1c3RlcjAyLCBmZWNoYV9jbnQsIHRtYXgsIHRtaW4sIHByZWNpcCwgbmV2YWRhLCBwcm9mX25pZXZlLCBsb25naXR1ZCwgbGF0aXR1ZCwgYWx0aXR1ZCkKICBkZi5jbHVzdGVyMDMgPC0gc2VsZWN0KGRmLmNsdXN0ZXIwMywgZmVjaGFfY250LCB0bWF4LCB0bWluLCBwcmVjaXAsIG5ldmFkYSwgcHJvZl9uaWV2ZSwgbG9uZ2l0dWQsIGxhdGl0dWQsIGFsdGl0dWQpCiAgZGYuY2x1c3RlcjA0IDwtIHNlbGVjdChkZi5jbHVzdGVyMDQsIGZlY2hhX2NudCwgdG1heCwgdG1pbiwgcHJlY2lwLCBuZXZhZGEsIHByb2ZfbmlldmUsIGxvbmdpdHVkLCBsYXRpdHVkLCBhbHRpdHVkKQogIGRmLmNsdXN0ZXIwNSA8LSBzZWxlY3QoZGYuY2x1c3RlcjA1LCBmZWNoYV9jbnQsIHRtYXgsIHRtaW4sIHByZWNpcCwgbmV2YWRhLCBwcm9mX25pZXZlLCBsb25naXR1ZCwgbGF0aXR1ZCwgYWx0aXR1ZCkKfQpgYGAKCmBgYHtyfQppZiAoIWVtcHR5X25vZGVzKSBzdW1tYXJ5KGRmLmNsdXN0ZXIwMSkKaWYgKCFlbXB0eV9ub2Rlcykgc3VtbWFyeShkZi5jbHVzdGVyMDIpCmlmICghZW1wdHlfbm9kZXMpIHN1bW1hcnkoZGYuY2x1c3RlcjAzKQppZiAoIWVtcHR5X25vZGVzKSBzdW1tYXJ5KGRmLmNsdXN0ZXIwNCkKaWYgKCFlbXB0eV9ub2Rlcykgc3VtbWFyeShkZi5jbHVzdGVyMDUpCmBgYAoKIyMjIyBOw7ptZXJvIGRlIGVsZW1lbnRvcyBlbiBjYWRhIGNsw7pzdGVyCgpgYGB7cn0KaWYgKCFlbXB0eV9ub2RlcykgewogIGRmLmNsdXN0ZXJzLmRpbSA8LSBjKGRpbShkZi5jbHVzdGVyMDEpWzFdLCBkaW0oZGYuY2x1c3RlcjAyKVsxXSwgZGltKGRmLmNsdXN0ZXIwMylbMV0sIGRpbShkZi5jbHVzdGVyMDQpWzFdLCBkaW0oZGYuY2x1c3RlcjA1KVsxXSkKICBiYXJwbG90KGRmLmNsdXN0ZXJzLmRpbSwKICAgICAgICAgIG5hbWVzLmFyZyA9IGMoImNsdXN0ZXIwMSIsICJjbHVzdGVyMDIiLCAiY2x1c3RlcjAzIiwgImNsdXN0ZXIwNCIsICJjbHVzdGVyMDUiKSwKICAgICAgICAgIGNvbCA9ICJzdGVlbGJsdWUxIikKfQpgYGAKCiMjIyMgRGlzdHJpYnVjacOzbiBkZSBsb3MgZGF0b3MKCmBgYHtyIGZpZy5oZWlnaHQ9N30KaWYgKCFlbXB0eV9ub2RlcykgbXByLmhpc3QoZGYuY2x1c3RlcjAxKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuaGlzdChkZi5jbHVzdGVyMDIpCmlmICghZW1wdHlfbm9kZXMpIG1wci5oaXN0KGRmLmNsdXN0ZXIwMykKaWYgKCFlbXB0eV9ub2RlcykgbXByLmhpc3QoZGYuY2x1c3RlcjA0KQppZiAoIWVtcHR5X25vZGVzKSBtcHIuaGlzdChkZi5jbHVzdGVyMDUpCmBgYAoKYGBge3IgZmlnLmhlaWdodD01fQppZiAoIWVtcHR5X25vZGVzKSBtcHIuYm94cGxvdChkZi5jbHVzdGVyMDEpCmlmICghZW1wdHlfbm9kZXMpIG1wci5ib3hwbG90KGRmLmNsdXN0ZXIwMikKaWYgKCFlbXB0eV9ub2RlcykgbXByLmJveHBsb3QoZGYuY2x1c3RlcjAzKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuYm94cGxvdChkZi5jbHVzdGVyMDQpCmlmICghZW1wdHlfbm9kZXMpIG1wci5ib3hwbG90KGRmLmNsdXN0ZXIwNSkKYGBgCgojIyMgTG9jYWxpemFjacOzbiBnZW9ncsOhZmljYSBkZSBsYXMgZXN0YWNpb25lcyBkZSBtZWRpZGEgZGUgY2FkYSBjbHVzdGVyCgpgYGB7cn0KIyBBZ3J1cGEgcG9yIGxvbmdpdHVkIHkgbGF0aXR1ZCBwYXJhIHJlbGxlbmFyIGVsIG1hcGEgY29uIG1lbm9zIGRhdG9zLgppZiAoIWVtcHR5X25vZGVzKSB7CiAgZGYuY2x1c3RlcjAxLmdyb3VwZWQgPC0gbXByLmdyb3VwX2J5X2dlbyhkZi5jbHVzdGVyMDEpCiAgZGYuY2x1c3RlcjAyLmdyb3VwZWQgPC0gbXByLmdyb3VwX2J5X2dlbyhkZi5jbHVzdGVyMDIpCiAgZGYuY2x1c3RlcjAzLmdyb3VwZWQgPC0gbXByLmdyb3VwX2J5X2dlbyhkZi5jbHVzdGVyMDMpCiAgZGYuY2x1c3RlcjA0Lmdyb3VwZWQgPC0gbXByLmdyb3VwX2J5X2dlbyhkZi5jbHVzdGVyMDQpCiAgZGYuY2x1c3RlcjA1Lmdyb3VwZWQgPC0gbXByLmdyb3VwX2J5X2dlbyhkZi5jbHVzdGVyMDUpCn0KYGBgCgpgYGB7cn0KaWYgKCFlbXB0eV9ub2RlcykgbXByLmRyYXdfbWFwKHNwYWluLCBkZi5jbHVzdGVyMDEuZ3JvdXBlZCkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmRyYXdfbWFwKHNwYWluLCBkZi5jbHVzdGVyMDIuZ3JvdXBlZCkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmRyYXdfbWFwKHNwYWluLCBkZi5jbHVzdGVyMDMuZ3JvdXBlZCkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmRyYXdfbWFwKHNwYWluLCBkZi5jbHVzdGVyMDQuZ3JvdXBlZCkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmRyYXdfbWFwKHNwYWluLCBkZi5jbHVzdGVyMDUuZ3JvdXBlZCkKYGBgCgojIyBWaXN1YWxpemFjacOzbiBkZSA2IGNsw7pzdGVyZXM6CgpgYGB7cn0KaWYgKCFlbXB0eV9ub2RlcykgewogIHBsb3QoaGFjLCBoYW5nPS0xLCBsYWJlbHM9RikKICByZWN0LmhjbHVzdChoYWMsIGs9NikKfQpgYGAKCiMjIyBWaXN1YWxpemFjacOzbiBkZSBsb3MgY2zDunN0ZXJzIGVuIGVsIG1hcGEKCkEgcXXDqSBjbMO6c3RlciBwZXJ0ZW5lY2UgY2FkYSBub2RvIGRlbCBtYXBhIGRlIGtvaG9uZW46CgpgYGB7cn0KaWYgKCFlbXB0eV9ub2RlcykgewogIGdyb3VwcyA8LSBjdXRyZWUoaGFjLCBrPTYpCiAgcGxvdChtb2RlbCwgdHlwZT0ibWFwcGluZyIsCiAgICBiZ2NvbD1jKCJzdGVlbGJsdWUxIiwic2llbm5hMSIsInllbGxvd2dyZWVuIiwicmVkIiwiYmx1ZSIsInllbGxvdyIsInB1cnBsZSIsImdyZWVuIiwid2hpdGUiLCIjMWY3N2I0IiwgJyNmZjdmMGUnLCAnIzJjYTAyYycsICcjZDYyNzI4JywgJyM5NDY3YmQnLCAnIzhjNTY0YicsICcjZTM3N2MyJylbZ3JvdXBzXSwKICAgIHNoYXBlID0gInN0cmFpZ2h0IiwgbGFiZWxzID0gIiIpCiAgYWRkLmNsdXN0ZXIuYm91bmRhcmllcyhtb2RlbCwgY2x1c3RlcmluZz1ncm91cHMpCn0KYGBgCgojIyMgQW7DoWxpc2lzIGRlIGxhcyBvYnNlcnZhY2lvbmVzIGRlIGNhZGEgY2x1c3RlcgoKYGBge3J9CmlmICghZW1wdHlfbm9kZXMpIHsKICAjIEFzaWduYW1vcyBhIGNhZGEgcmVnaXN0cm8gc3UgY2zDunN0ZXIKICBkZiRjbHVzdGVyIDwtIGdyb3Vwc1ttb2RlbCR1bml0LmNsYXNzaWZdCn0KYGBgCgpOdWV2b3MgZGF0YWZyYW1lcyBwb3IgY2x1c3RlcgoKYGBge3J9CmlmICghZW1wdHlfbm9kZXMpIHsKICAjIENyZW8gbnVldm9zIGRhdGFmcmFtZXMsIHVubyBwb3IgY2FkYSBjbMO6c3Rlci4KICBkZi5jbHVzdGVyMDEgPC0gc3Vic2V0KGRmLCBjbHVzdGVyPT0xKQogIGRmLmNsdXN0ZXIwMiA8LSBzdWJzZXQoZGYsIGNsdXN0ZXI9PTIpCiAgZGYuY2x1c3RlcjAzIDwtIHN1YnNldChkZiwgY2x1c3Rlcj09MykKICBkZi5jbHVzdGVyMDQgPC0gc3Vic2V0KGRmLCBjbHVzdGVyPT00KQogIGRmLmNsdXN0ZXIwNSA8LSBzdWJzZXQoZGYsIGNsdXN0ZXI9PTUpCiAgZGYuY2x1c3RlcjA2IDwtIHN1YnNldChkZiwgY2x1c3Rlcj09NikKCiAgIyBFeHRyYWlnbyBkZWwgZGF0YWZyYW1lIGxhcyBmZWF0dXJlcy4KICBkZi5jbHVzdGVyMDEgPC0gc2VsZWN0KGRmLmNsdXN0ZXIwMSwgZmVjaGFfY250LCB0bWF4LCB0bWluLCBwcmVjaXAsIG5ldmFkYSwgcHJvZl9uaWV2ZSwgbG9uZ2l0dWQsIGxhdGl0dWQsIGFsdGl0dWQpCiAgZGYuY2x1c3RlcjAyIDwtIHNlbGVjdChkZi5jbHVzdGVyMDIsIGZlY2hhX2NudCwgdG1heCwgdG1pbiwgcHJlY2lwLCBuZXZhZGEsIHByb2ZfbmlldmUsIGxvbmdpdHVkLCBsYXRpdHVkLCBhbHRpdHVkKQogIGRmLmNsdXN0ZXIwMyA8LSBzZWxlY3QoZGYuY2x1c3RlcjAzLCBmZWNoYV9jbnQsIHRtYXgsIHRtaW4sIHByZWNpcCwgbmV2YWRhLCBwcm9mX25pZXZlLCBsb25naXR1ZCwgbGF0aXR1ZCwgYWx0aXR1ZCkKICBkZi5jbHVzdGVyMDQgPC0gc2VsZWN0KGRmLmNsdXN0ZXIwNCwgZmVjaGFfY250LCB0bWF4LCB0bWluLCBwcmVjaXAsIG5ldmFkYSwgcHJvZl9uaWV2ZSwgbG9uZ2l0dWQsIGxhdGl0dWQsIGFsdGl0dWQpCiAgZGYuY2x1c3RlcjA1IDwtIHNlbGVjdChkZi5jbHVzdGVyMDUsIGZlY2hhX2NudCwgdG1heCwgdG1pbiwgcHJlY2lwLCBuZXZhZGEsIHByb2ZfbmlldmUsIGxvbmdpdHVkLCBsYXRpdHVkLCBhbHRpdHVkKQogIGRmLmNsdXN0ZXIwNiA8LSBzZWxlY3QoZGYuY2x1c3RlcjA2LCBmZWNoYV9jbnQsIHRtYXgsIHRtaW4sIHByZWNpcCwgbmV2YWRhLCBwcm9mX25pZXZlLCBsb25naXR1ZCwgbGF0aXR1ZCwgYWx0aXR1ZCkKfQpgYGAKCmBgYHtyfQppZiAoIWVtcHR5X25vZGVzKSBzdW1tYXJ5KGRmLmNsdXN0ZXIwMSkKaWYgKCFlbXB0eV9ub2Rlcykgc3VtbWFyeShkZi5jbHVzdGVyMDIpCmlmICghZW1wdHlfbm9kZXMpIHN1bW1hcnkoZGYuY2x1c3RlcjAzKQppZiAoIWVtcHR5X25vZGVzKSBzdW1tYXJ5KGRmLmNsdXN0ZXIwNCkKaWYgKCFlbXB0eV9ub2Rlcykgc3VtbWFyeShkZi5jbHVzdGVyMDUpCmlmICghZW1wdHlfbm9kZXMpIHN1bW1hcnkoZGYuY2x1c3RlcjA2KQpgYGAKCiMjIyMgTsO6bWVybyBkZSBlbGVtZW50b3MgZW4gY2FkYSBjbMO6c3RlcgoKYGBge3J9CmlmICghZW1wdHlfbm9kZXMpIHsKICBkZi5jbHVzdGVycy5kaW0gPC0gYyhkaW0oZGYuY2x1c3RlcjAxKVsxXSwgZGltKGRmLmNsdXN0ZXIwMilbMV0sIGRpbShkZi5jbHVzdGVyMDMpWzFdLCBkaW0oZGYuY2x1c3RlcjA0KVsxXSwgZGltKGRmLmNsdXN0ZXIwNSlbMV0sIGRpbShkZi5jbHVzdGVyMDYpWzFdKQogIGJhcnBsb3QoZGYuY2x1c3RlcnMuZGltLAogICAgICAgICAgbmFtZXMuYXJnID0gYygiY2x1c3RlcjAxIiwgImNsdXN0ZXIwMiIsICJjbHVzdGVyMDMiLCAiY2x1c3RlcjA0IiwgImNsdXN0ZXIwNSIsICJjbHVzdGVyMDYiKSwKICAgICAgICAgIGNvbCA9ICJzdGVlbGJsdWUxIikKfQpgYGAKCiMjIyMgRGlzdHJpYnVjacOzbiBkZSBsb3MgZGF0b3MKCmBgYHtyIGZpZy5oZWlnaHQ9N30KaWYgKCFlbXB0eV9ub2RlcykgbXByLmhpc3QoZGYuY2x1c3RlcjAxKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuaGlzdChkZi5jbHVzdGVyMDIpCmlmICghZW1wdHlfbm9kZXMpIG1wci5oaXN0KGRmLmNsdXN0ZXIwMykKaWYgKCFlbXB0eV9ub2RlcykgbXByLmhpc3QoZGYuY2x1c3RlcjA0KQppZiAoIWVtcHR5X25vZGVzKSBtcHIuaGlzdChkZi5jbHVzdGVyMDUpCmlmICghZW1wdHlfbm9kZXMpIG1wci5oaXN0KGRmLmNsdXN0ZXIwNikKYGBgCgpgYGB7ciBmaWcuaGVpZ2h0PTV9CmlmICghZW1wdHlfbm9kZXMpIG1wci5ib3hwbG90KGRmLmNsdXN0ZXIwMSkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmJveHBsb3QoZGYuY2x1c3RlcjAyKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuYm94cGxvdChkZi5jbHVzdGVyMDMpCmlmICghZW1wdHlfbm9kZXMpIG1wci5ib3hwbG90KGRmLmNsdXN0ZXIwNCkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmJveHBsb3QoZGYuY2x1c3RlcjA1KQppZiAoIWVtcHR5X25vZGVzKSBtcHIuYm94cGxvdChkZi5jbHVzdGVyMDYpCmBgYAoKIyMjIExvY2FsaXphY2nDs24gZ2VvZ3LDoWZpY2EgZGUgbGFzIGVzdGFjaW9uZXMgZGUgbWVkaWRhIGRlIGNhZGEgY2x1c3RlcgoKYGBge3J9CiMgQWdydXBhIHBvciBsb25naXR1ZCB5IGxhdGl0dWQgcGFyYSByZWxsZW5hciBlbCBtYXBhIGNvbiBtZW5vcyBkYXRvcy4KaWYgKCFlbXB0eV9ub2RlcykgewogIGRmLmNsdXN0ZXIwMS5ncm91cGVkIDwtIG1wci5ncm91cF9ieV9nZW8oZGYuY2x1c3RlcjAxKQogIGRmLmNsdXN0ZXIwMi5ncm91cGVkIDwtIG1wci5ncm91cF9ieV9nZW8oZGYuY2x1c3RlcjAyKQogIGRmLmNsdXN0ZXIwMy5ncm91cGVkIDwtIG1wci5ncm91cF9ieV9nZW8oZGYuY2x1c3RlcjAzKQogIGRmLmNsdXN0ZXIwNC5ncm91cGVkIDwtIG1wci5ncm91cF9ieV9nZW8oZGYuY2x1c3RlcjA0KQogIGRmLmNsdXN0ZXIwNS5ncm91cGVkIDwtIG1wci5ncm91cF9ieV9nZW8oZGYuY2x1c3RlcjA1KQogIGRmLmNsdXN0ZXIwNi5ncm91cGVkIDwtIG1wci5ncm91cF9ieV9nZW8oZGYuY2x1c3RlcjA2KQp9CmBgYAoKYGBge3J9CmlmICghZW1wdHlfbm9kZXMpIG1wci5kcmF3X21hcChzcGFpbiwgZGYuY2x1c3RlcjAxLmdyb3VwZWQpCmlmICghZW1wdHlfbm9kZXMpIG1wci5kcmF3X21hcChzcGFpbiwgZGYuY2x1c3RlcjAyLmdyb3VwZWQpCmlmICghZW1wdHlfbm9kZXMpIG1wci5kcmF3X21hcChzcGFpbiwgZGYuY2x1c3RlcjAzLmdyb3VwZWQpCmlmICghZW1wdHlfbm9kZXMpIG1wci5kcmF3X21hcChzcGFpbiwgZGYuY2x1c3RlcjA0Lmdyb3VwZWQpCmlmICghZW1wdHlfbm9kZXMpIG1wci5kcmF3X21hcChzcGFpbiwgZGYuY2x1c3RlcjA1Lmdyb3VwZWQpCmlmICghZW1wdHlfbm9kZXMpIG1wci5kcmF3X21hcChzcGFpbiwgZGYuY2x1c3RlcjA2Lmdyb3VwZWQpCmBgYAoKIyMgVmlzdWFsaXphY2nDs24gZGUgOCBjbMO6c3RlcmVzOgoKYGBge3J9CmlmICghZW1wdHlfbm9kZXMpIHsKICBwbG90KGhhYywgaGFuZz0tMSwgbGFiZWxzPUYpCiAgcmVjdC5oY2x1c3QoaGFjLCBrPTgpCn0KYGBgCgojIyMgVmlzdWFsaXphY2nDs24gZGUgbG9zIGNsw7pzdGVycyBlbiBlbCBtYXBhCgpBIHF1w6kgY2zDunN0ZXIgcGVydGVuZWNlIGNhZGEgbm9kbyBkZWwgbWFwYSBkZSBrb2hvbmVuOgoKYGBge3J9CmlmICghZW1wdHlfbm9kZXMpIHsKICBncm91cHMgPC0gY3V0cmVlKGhhYywgaz04KQogIHBsb3QobW9kZWwsIHR5cGU9Im1hcHBpbmciLAogICAgYmdjb2w9Yygic3RlZWxibHVlMSIsInNpZW5uYTEiLCJ5ZWxsb3dncmVlbiIsInJlZCIsImJsdWUiLCJ5ZWxsb3ciLCJwdXJwbGUiLCJncmVlbiIsIndoaXRlIiwiIzFmNzdiNCIsICcjZmY3ZjBlJywgJyMyY2EwMmMnLCAnI2Q2MjcyOCcsICcjOTQ2N2JkJywgJyM4YzU2NGInLCAnI2UzNzdjMicpW2dyb3Vwc10sCiAgICBzaGFwZSA9ICJzdHJhaWdodCIsIGxhYmVscyA9ICIiKQogIGFkZC5jbHVzdGVyLmJvdW5kYXJpZXMobW9kZWwsIGNsdXN0ZXJpbmc9Z3JvdXBzKQp9CmBgYAoKIyMjIEFuw6FsaXNpcyBkZSBsYXMgb2JzZXJ2YWNpb25lcyBkZSBjYWRhIGNsdXN0ZXIKCmBgYHtyfQppZiAoIWVtcHR5X25vZGVzKSB7CiAgIyBBc2lnbmFtb3MgYSBjYWRhIHJlZ2lzdHJvIHN1IGNsw7pzdGVyCiAgZGYkY2x1c3RlciA8LSBncm91cHNbbW9kZWwkdW5pdC5jbGFzc2lmXQp9CmBgYAoKTnVldm9zIGRhdGFmcmFtZXMgcG9yIGNsdXN0ZXIKCmBgYHtyfQppZiAoIWVtcHR5X25vZGVzKSB7CiAgIyBDcmVvIG51ZXZvcyBkYXRhZnJhbWVzLCB1bm8gcG9yIGNhZGEgY2zDunN0ZXIuCiAgZGYuY2x1c3RlcjAxIDwtIHN1YnNldChkZiwgY2x1c3Rlcj09MSkKICBkZi5jbHVzdGVyMDIgPC0gc3Vic2V0KGRmLCBjbHVzdGVyPT0yKQogIGRmLmNsdXN0ZXIwMyA8LSBzdWJzZXQoZGYsIGNsdXN0ZXI9PTMpCiAgZGYuY2x1c3RlcjA0IDwtIHN1YnNldChkZiwgY2x1c3Rlcj09NCkKICBkZi5jbHVzdGVyMDUgPC0gc3Vic2V0KGRmLCBjbHVzdGVyPT01KQogIGRmLmNsdXN0ZXIwNiA8LSBzdWJzZXQoZGYsIGNsdXN0ZXI9PTYpCiAgZGYuY2x1c3RlcjA3IDwtIHN1YnNldChkZiwgY2x1c3Rlcj09NykKICBkZi5jbHVzdGVyMDggPC0gc3Vic2V0KGRmLCBjbHVzdGVyPT04KQoKICAjIEV4dHJhaWdvIGRlbCBkYXRhZnJhbWUgbGFzIGZlYXR1cmVzLgogIGRmLmNsdXN0ZXIwMSA8LSBzZWxlY3QoZGYuY2x1c3RlcjAxLCBmZWNoYV9jbnQsIHRtYXgsIHRtaW4sIHByZWNpcCwgbmV2YWRhLCBwcm9mX25pZXZlLCBsb25naXR1ZCwgbGF0aXR1ZCwgYWx0aXR1ZCkKICBkZi5jbHVzdGVyMDIgPC0gc2VsZWN0KGRmLmNsdXN0ZXIwMiwgZmVjaGFfY250LCB0bWF4LCB0bWluLCBwcmVjaXAsIG5ldmFkYSwgcHJvZl9uaWV2ZSwgbG9uZ2l0dWQsIGxhdGl0dWQsIGFsdGl0dWQpCiAgZGYuY2x1c3RlcjAzIDwtIHNlbGVjdChkZi5jbHVzdGVyMDMsIGZlY2hhX2NudCwgdG1heCwgdG1pbiwgcHJlY2lwLCBuZXZhZGEsIHByb2ZfbmlldmUsIGxvbmdpdHVkLCBsYXRpdHVkLCBhbHRpdHVkKQogIGRmLmNsdXN0ZXIwNCA8LSBzZWxlY3QoZGYuY2x1c3RlcjA0LCBmZWNoYV9jbnQsIHRtYXgsIHRtaW4sIHByZWNpcCwgbmV2YWRhLCBwcm9mX25pZXZlLCBsb25naXR1ZCwgbGF0aXR1ZCwgYWx0aXR1ZCkKICBkZi5jbHVzdGVyMDUgPC0gc2VsZWN0KGRmLmNsdXN0ZXIwNSwgZmVjaGFfY250LCB0bWF4LCB0bWluLCBwcmVjaXAsIG5ldmFkYSwgcHJvZl9uaWV2ZSwgbG9uZ2l0dWQsIGxhdGl0dWQsIGFsdGl0dWQpCiAgZGYuY2x1c3RlcjA2IDwtIHNlbGVjdChkZi5jbHVzdGVyMDYsIGZlY2hhX2NudCwgdG1heCwgdG1pbiwgcHJlY2lwLCBuZXZhZGEsIHByb2ZfbmlldmUsIGxvbmdpdHVkLCBsYXRpdHVkLCBhbHRpdHVkKQogIGRmLmNsdXN0ZXIwNyA8LSBzZWxlY3QoZGYuY2x1c3RlcjA3LCBmZWNoYV9jbnQsIHRtYXgsIHRtaW4sIHByZWNpcCwgbmV2YWRhLCBwcm9mX25pZXZlLCBsb25naXR1ZCwgbGF0aXR1ZCwgYWx0aXR1ZCkKICBkZi5jbHVzdGVyMDggPC0gc2VsZWN0KGRmLmNsdXN0ZXIwOCwgZmVjaGFfY250LCB0bWF4LCB0bWluLCBwcmVjaXAsIG5ldmFkYSwgcHJvZl9uaWV2ZSwgbG9uZ2l0dWQsIGxhdGl0dWQsIGFsdGl0dWQpCn0KYGBgCgpgYGB7cn0KaWYgKCFlbXB0eV9ub2Rlcykgc3VtbWFyeShkZi5jbHVzdGVyMDEpCmlmICghZW1wdHlfbm9kZXMpIHN1bW1hcnkoZGYuY2x1c3RlcjAyKQppZiAoIWVtcHR5X25vZGVzKSBzdW1tYXJ5KGRmLmNsdXN0ZXIwMykKaWYgKCFlbXB0eV9ub2Rlcykgc3VtbWFyeShkZi5jbHVzdGVyMDQpCmlmICghZW1wdHlfbm9kZXMpIHN1bW1hcnkoZGYuY2x1c3RlcjA1KQppZiAoIWVtcHR5X25vZGVzKSBzdW1tYXJ5KGRmLmNsdXN0ZXIwNikKaWYgKCFlbXB0eV9ub2Rlcykgc3VtbWFyeShkZi5jbHVzdGVyMDcpCmlmICghZW1wdHlfbm9kZXMpIHN1bW1hcnkoZGYuY2x1c3RlcjA4KQpgYGAKCiMjIyMgTsO6bWVybyBkZSBlbGVtZW50b3MgZW4gY2FkYSBjbMO6c3RlcgoKYGBge3J9CmlmICghZW1wdHlfbm9kZXMpIHsKICBkZi5jbHVzdGVycy5kaW0gPC0gYyhkaW0oZGYuY2x1c3RlcjAxKVsxXSwgZGltKGRmLmNsdXN0ZXIwMilbMV0sIGRpbShkZi5jbHVzdGVyMDMpWzFdLCBkaW0oZGYuY2x1c3RlcjA0KVsxXSwgZGltKGRmLmNsdXN0ZXIwNSlbMV0sIGRpbShkZi5jbHVzdGVyMDYpWzFdLCBkaW0oZGYuY2x1c3RlcjA3KVsxXSwgZGltKGRmLmNsdXN0ZXIwOClbMV0pCiAgYmFycGxvdChkZi5jbHVzdGVycy5kaW0sCiAgICAgICAgICBuYW1lcy5hcmcgPSBjKCJjbHVzdGVyMDEiLCAiY2x1c3RlcjAyIiwgImNsdXN0ZXIwMyIsICJjbHVzdGVyMDQiLCAiY2x1c3RlcjA1IiwgImNsdXN0ZXIwNiIsICJjbHVzdGVyMDciLCAiY2x1c3RlcjA4IiksCiAgICAgICAgICBjb2wgPSAic3RlZWxibHVlMSIpCn0KYGBgCgojIyMjIERpc3RyaWJ1Y2nDs24gZGUgbG9zIGRhdG9zCgpgYGB7ciBmaWcuaGVpZ2h0PTd9CmlmICghZW1wdHlfbm9kZXMpIG1wci5oaXN0KGRmLmNsdXN0ZXIwMSkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmhpc3QoZGYuY2x1c3RlcjAyKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuaGlzdChkZi5jbHVzdGVyMDMpCmlmICghZW1wdHlfbm9kZXMpIG1wci5oaXN0KGRmLmNsdXN0ZXIwNCkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmhpc3QoZGYuY2x1c3RlcjA1KQppZiAoIWVtcHR5X25vZGVzKSBtcHIuaGlzdChkZi5jbHVzdGVyMDYpCmlmICghZW1wdHlfbm9kZXMpIG1wci5oaXN0KGRmLmNsdXN0ZXIwNykKaWYgKCFlbXB0eV9ub2RlcykgbXByLmhpc3QoZGYuY2x1c3RlcjA4KQpgYGAKCmBgYHtyIGZpZy5oZWlnaHQ9NX0KaWYgKCFlbXB0eV9ub2RlcykgbXByLmJveHBsb3QoZGYuY2x1c3RlcjAxKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuYm94cGxvdChkZi5jbHVzdGVyMDIpCmlmICghZW1wdHlfbm9kZXMpIG1wci5ib3hwbG90KGRmLmNsdXN0ZXIwMykKaWYgKCFlbXB0eV9ub2RlcykgbXByLmJveHBsb3QoZGYuY2x1c3RlcjA0KQppZiAoIWVtcHR5X25vZGVzKSBtcHIuYm94cGxvdChkZi5jbHVzdGVyMDUpCmlmICghZW1wdHlfbm9kZXMpIG1wci5ib3hwbG90KGRmLmNsdXN0ZXIwNikKaWYgKCFlbXB0eV9ub2RlcykgbXByLmJveHBsb3QoZGYuY2x1c3RlcjA3KQppZiAoIWVtcHR5X25vZGVzKSBtcHIuYm94cGxvdChkZi5jbHVzdGVyMDgpCmBgYAoKIyMjIExvY2FsaXphY2nDs24gZ2VvZ3LDoWZpY2EgZGUgbGFzIGVzdGFjaW9uZXMgZGUgbWVkaWRhIGRlIGNhZGEgY2x1c3RlcgoKYGBge3J9CiMgQWdydXBhIHBvciBsb25naXR1ZCB5IGxhdGl0dWQgcGFyYSByZWxsZW5hciBlbCBtYXBhIGNvbiBtZW5vcyBkYXRvcy4KaWYgKCFlbXB0eV9ub2RlcykgewogIGRmLmNsdXN0ZXIwMS5ncm91cGVkIDwtIG1wci5ncm91cF9ieV9nZW8oZGYuY2x1c3RlcjAxKQogIGRmLmNsdXN0ZXIwMi5ncm91cGVkIDwtIG1wci5ncm91cF9ieV9nZW8oZGYuY2x1c3RlcjAyKQogIGRmLmNsdXN0ZXIwMy5ncm91cGVkIDwtIG1wci5ncm91cF9ieV9nZW8oZGYuY2x1c3RlcjAzKQogIGRmLmNsdXN0ZXIwNC5ncm91cGVkIDwtIG1wci5ncm91cF9ieV9nZW8oZGYuY2x1c3RlcjA0KQogIGRmLmNsdXN0ZXIwNS5ncm91cGVkIDwtIG1wci5ncm91cF9ieV9nZW8oZGYuY2x1c3RlcjA1KQogIGRmLmNsdXN0ZXIwNi5ncm91cGVkIDwtIG1wci5ncm91cF9ieV9nZW8oZGYuY2x1c3RlcjA2KQogIGRmLmNsdXN0ZXIwNy5ncm91cGVkIDwtIG1wci5ncm91cF9ieV9nZW8oZGYuY2x1c3RlcjA3KQogIGRmLmNsdXN0ZXIwOC5ncm91cGVkIDwtIG1wci5ncm91cF9ieV9nZW8oZGYuY2x1c3RlcjA4KQp9CmBgYAoKYGBge3J9CmlmICghZW1wdHlfbm9kZXMpIG1wci5kcmF3X21hcChzcGFpbiwgZGYuY2x1c3RlcjAxLmdyb3VwZWQpCmlmICghZW1wdHlfbm9kZXMpIG1wci5kcmF3X21hcChzcGFpbiwgZGYuY2x1c3RlcjAyLmdyb3VwZWQpCmlmICghZW1wdHlfbm9kZXMpIG1wci5kcmF3X21hcChzcGFpbiwgZGYuY2x1c3RlcjAzLmdyb3VwZWQpCmlmICghZW1wdHlfbm9kZXMpIG1wci5kcmF3X21hcChzcGFpbiwgZGYuY2x1c3RlcjA0Lmdyb3VwZWQpCmlmICghZW1wdHlfbm9kZXMpIG1wci5kcmF3X21hcChzcGFpbiwgZGYuY2x1c3RlcjA1Lmdyb3VwZWQpCmlmICghZW1wdHlfbm9kZXMpIG1wci5kcmF3X21hcChzcGFpbiwgZGYuY2x1c3RlcjA2Lmdyb3VwZWQpCmlmICghZW1wdHlfbm9kZXMpIG1wci5kcmF3X21hcChzcGFpbiwgZGYuY2x1c3RlcjA3Lmdyb3VwZWQpCmlmICghZW1wdHlfbm9kZXMpIG1wci5kcmF3X21hcChzcGFpbiwgZGYuY2x1c3RlcjA4Lmdyb3VwZWQpCmBgYAoKIyMgVmlzdWFsaXphY2nDs24gZGUgMTAgY2zDunN0ZXJlczoKCmBgYHtyfQppZiAoIWVtcHR5X25vZGVzKSB7CiAgcGxvdChoYWMsIGhhbmc9LTEsIGxhYmVscz1GKQogIHJlY3QuaGNsdXN0KGhhYywgaz0xMCkKfQpgYGAKCiMjIyBWaXN1YWxpemFjacOzbiBkZSBsb3MgY2zDunN0ZXJzIGVuIGVsIG1hcGEKCkEgcXXDqSBjbMO6c3RlciBwZXJ0ZW5lY2UgY2FkYSBub2RvIGRlbCBtYXBhIGRlIGtvaG9uZW46CgpgYGB7cn0KaWYgKCFlbXB0eV9ub2RlcykgewogIGdyb3VwcyA8LSBjdXRyZWUoaGFjLCBrPTEwKQogIHBsb3QobW9kZWwsIHR5cGU9Im1hcHBpbmciLAogICAgYmdjb2w9Yygic3RlZWxibHVlMSIsInNpZW5uYTEiLCJ5ZWxsb3dncmVlbiIsInJlZCIsImJsdWUiLCJ5ZWxsb3ciLCJwdXJwbGUiLCJncmVlbiIsIndoaXRlIiwiIzFmNzdiNCIsICcjZmY3ZjBlJywgJyMyY2EwMmMnLCAnI2Q2MjcyOCcsICcjOTQ2N2JkJywgJyM4YzU2NGInLCAnI2UzNzdjMicpW2dyb3Vwc10sCiAgICBzaGFwZSA9ICJzdHJhaWdodCIsIGxhYmVscyA9ICIiKQogIGFkZC5jbHVzdGVyLmJvdW5kYXJpZXMobW9kZWwsIGNsdXN0ZXJpbmc9Z3JvdXBzKQp9CmBgYAoKIyMjIEFuw6FsaXNpcyBkZSBsYXMgb2JzZXJ2YWNpb25lcyBkZSBjYWRhIGNsdXN0ZXIKCmBgYHtyfQppZiAoIWVtcHR5X25vZGVzKSB7CiAgIyBBc2lnbmFtb3MgYSBjYWRhIHJlZ2lzdHJvIHN1IGNsw7pzdGVyCiAgZGYkY2x1c3RlciA8LSBncm91cHNbbW9kZWwkdW5pdC5jbGFzc2lmXQp9CmBgYAoKTnVldm9zIGRhdGFmcmFtZXMgcG9yIGNsdXN0ZXIKCmBgYHtyfQppZiAoIWVtcHR5X25vZGVzKSB7CiAgIyBDcmVvIG51ZXZvcyBkYXRhZnJhbWVzLCB1bm8gcG9yIGNhZGEgY2zDunN0ZXIuCiAgZGYuY2x1c3RlcjAxIDwtIHN1YnNldChkZiwgY2x1c3Rlcj09MSkKICBkZi5jbHVzdGVyMDIgPC0gc3Vic2V0KGRmLCBjbHVzdGVyPT0yKQogIGRmLmNsdXN0ZXIwMyA8LSBzdWJzZXQoZGYsIGNsdXN0ZXI9PTMpCiAgZGYuY2x1c3RlcjA0IDwtIHN1YnNldChkZiwgY2x1c3Rlcj09NCkKICBkZi5jbHVzdGVyMDUgPC0gc3Vic2V0KGRmLCBjbHVzdGVyPT01KQogIGRmLmNsdXN0ZXIwNiA8LSBzdWJzZXQoZGYsIGNsdXN0ZXI9PTYpCiAgZGYuY2x1c3RlcjA3IDwtIHN1YnNldChkZiwgY2x1c3Rlcj09NykKICBkZi5jbHVzdGVyMDggPC0gc3Vic2V0KGRmLCBjbHVzdGVyPT04KQogIGRmLmNsdXN0ZXIwOSA8LSBzdWJzZXQoZGYsIGNsdXN0ZXI9PTkpCiAgZGYuY2x1c3RlcjEwIDwtIHN1YnNldChkZiwgY2x1c3Rlcj09MTApCgogICMgRXh0cmFpZ28gZGVsIGRhdGFmcmFtZSBsYXMgZmVhdHVyZXMuCiAgZGYuY2x1c3RlcjAxIDwtIHNlbGVjdChkZi5jbHVzdGVyMDEsIGZlY2hhX2NudCwgdG1heCwgdG1pbiwgcHJlY2lwLCBuZXZhZGEsIHByb2ZfbmlldmUsIGxvbmdpdHVkLCBsYXRpdHVkLCBhbHRpdHVkKQogIGRmLmNsdXN0ZXIwMiA8LSBzZWxlY3QoZGYuY2x1c3RlcjAyLCBmZWNoYV9jbnQsIHRtYXgsIHRtaW4sIHByZWNpcCwgbmV2YWRhLCBwcm9mX25pZXZlLCBsb25naXR1ZCwgbGF0aXR1ZCwgYWx0aXR1ZCkKICBkZi5jbHVzdGVyMDMgPC0gc2VsZWN0KGRmLmNsdXN0ZXIwMywgZmVjaGFfY250LCB0bWF4LCB0bWluLCBwcmVjaXAsIG5ldmFkYSwgcHJvZl9uaWV2ZSwgbG9uZ2l0dWQsIGxhdGl0dWQsIGFsdGl0dWQpCiAgZGYuY2x1c3RlcjA0IDwtIHNlbGVjdChkZi5jbHVzdGVyMDQsIGZlY2hhX2NudCwgdG1heCwgdG1pbiwgcHJlY2lwLCBuZXZhZGEsIHByb2ZfbmlldmUsIGxvbmdpdHVkLCBsYXRpdHVkLCBhbHRpdHVkKQogIGRmLmNsdXN0ZXIwNSA8LSBzZWxlY3QoZGYuY2x1c3RlcjA1LCBmZWNoYV9jbnQsIHRtYXgsIHRtaW4sIHByZWNpcCwgbmV2YWRhLCBwcm9mX25pZXZlLCBsb25naXR1ZCwgbGF0aXR1ZCwgYWx0aXR1ZCkKICBkZi5jbHVzdGVyMDYgPC0gc2VsZWN0KGRmLmNsdXN0ZXIwNiwgZmVjaGFfY250LCB0bWF4LCB0bWluLCBwcmVjaXAsIG5ldmFkYSwgcHJvZl9uaWV2ZSwgbG9uZ2l0dWQsIGxhdGl0dWQsIGFsdGl0dWQpCiAgZGYuY2x1c3RlcjA3IDwtIHNlbGVjdChkZi5jbHVzdGVyMDcsIGZlY2hhX2NudCwgdG1heCwgdG1pbiwgcHJlY2lwLCBuZXZhZGEsIHByb2ZfbmlldmUsIGxvbmdpdHVkLCBsYXRpdHVkLCBhbHRpdHVkKQogIGRmLmNsdXN0ZXIwOCA8LSBzZWxlY3QoZGYuY2x1c3RlcjA4LCBmZWNoYV9jbnQsIHRtYXgsIHRtaW4sIHByZWNpcCwgbmV2YWRhLCBwcm9mX25pZXZlLCBsb25naXR1ZCwgbGF0aXR1ZCwgYWx0aXR1ZCkKICBkZi5jbHVzdGVyMDkgPC0gc2VsZWN0KGRmLmNsdXN0ZXIwOSwgZmVjaGFfY250LCB0bWF4LCB0bWluLCBwcmVjaXAsIG5ldmFkYSwgcHJvZl9uaWV2ZSwgbG9uZ2l0dWQsIGxhdGl0dWQsIGFsdGl0dWQpCiAgZGYuY2x1c3RlcjEwIDwtIHNlbGVjdChkZi5jbHVzdGVyMTAsIGZlY2hhX2NudCwgdG1heCwgdG1pbiwgcHJlY2lwLCBuZXZhZGEsIHByb2ZfbmlldmUsIGxvbmdpdHVkLCBsYXRpdHVkLCBhbHRpdHVkKQp9CmBgYAoKYGBge3J9CmlmICghZW1wdHlfbm9kZXMpIHN1bW1hcnkoZGYuY2x1c3RlcjAxKQppZiAoIWVtcHR5X25vZGVzKSBzdW1tYXJ5KGRmLmNsdXN0ZXIwMikKaWYgKCFlbXB0eV9ub2Rlcykgc3VtbWFyeShkZi5jbHVzdGVyMDMpCmlmICghZW1wdHlfbm9kZXMpIHN1bW1hcnkoZGYuY2x1c3RlcjA0KQppZiAoIWVtcHR5X25vZGVzKSBzdW1tYXJ5KGRmLmNsdXN0ZXIwNSkKaWYgKCFlbXB0eV9ub2Rlcykgc3VtbWFyeShkZi5jbHVzdGVyMDYpCmlmICghZW1wdHlfbm9kZXMpIHN1bW1hcnkoZGYuY2x1c3RlcjA3KQppZiAoIWVtcHR5X25vZGVzKSBzdW1tYXJ5KGRmLmNsdXN0ZXIwOCkKaWYgKCFlbXB0eV9ub2Rlcykgc3VtbWFyeShkZi5jbHVzdGVyMDkpCmlmICghZW1wdHlfbm9kZXMpIHN1bW1hcnkoZGYuY2x1c3RlcjEwKQpgYGAKCiMjIyMgTsO6bWVybyBkZSBlbGVtZW50b3MgZW4gY2FkYSBjbMO6c3RlcgoKYGBge3J9CmlmICghZW1wdHlfbm9kZXMpIHsKICBkZi5jbHVzdGVycy5kaW0gPC0gYyhkaW0oZGYuY2x1c3RlcjAxKVsxXSwgZGltKGRmLmNsdXN0ZXIwMilbMV0sIGRpbShkZi5jbHVzdGVyMDMpWzFdLCBkaW0oZGYuY2x1c3RlcjA0KVsxXSwgZGltKGRmLmNsdXN0ZXIwNSlbMV0sIGRpbShkZi5jbHVzdGVyMDYpWzFdLCBkaW0oZGYuY2x1c3RlcjA3KVsxXSwgZGltKGRmLmNsdXN0ZXIwOClbMV0sIGRpbShkZi5jbHVzdGVyMDkpWzFdLCBkaW0oZGYuY2x1c3RlcjEwKVsxXSkKICBiYXJwbG90KGRmLmNsdXN0ZXJzLmRpbSwKICAgICAgICAgIG5hbWVzLmFyZyA9IGMoImNsdXN0ZXIwMSIsICJjbHVzdGVyMDIiLCAiY2x1c3RlcjAzIiwgImNsdXN0ZXIwNCIsICJjbHVzdGVyMDUiLCAiY2x1c3RlcjA2IiwgImNsdXN0ZXIwNyIsICJjbHVzdGVyMDgiLCAiY2x1c3RlcjA5IiwgImNsdXN0ZXIxMCIpLAogICAgICAgICAgY29sID0gInN0ZWVsYmx1ZTEiKQp9CmBgYAoKIyMjIyBEaXN0cmlidWNpw7NuIGRlIGxvcyBkYXRvcwoKYGBge3IgZmlnLmhlaWdodD03fQppZiAoIWVtcHR5X25vZGVzKSBtcHIuaGlzdChkZi5jbHVzdGVyMDEpCmlmICghZW1wdHlfbm9kZXMpIG1wci5oaXN0KGRmLmNsdXN0ZXIwMikKaWYgKCFlbXB0eV9ub2RlcykgbXByLmhpc3QoZGYuY2x1c3RlcjAzKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuaGlzdChkZi5jbHVzdGVyMDQpCmlmICghZW1wdHlfbm9kZXMpIG1wci5oaXN0KGRmLmNsdXN0ZXIwNSkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmhpc3QoZGYuY2x1c3RlcjA2KQppZiAoIWVtcHR5X25vZGVzKSBtcHIuaGlzdChkZi5jbHVzdGVyMDcpCmlmICghZW1wdHlfbm9kZXMpIG1wci5oaXN0KGRmLmNsdXN0ZXIwOCkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmhpc3QoZGYuY2x1c3RlcjA5KQppZiAoIWVtcHR5X25vZGVzKSBtcHIuaGlzdChkZi5jbHVzdGVyMTApCmBgYAoKYGBge3IgZmlnLmhlaWdodD01fQppZiAoIWVtcHR5X25vZGVzKSBtcHIuYm94cGxvdChkZi5jbHVzdGVyMDEpCmlmICghZW1wdHlfbm9kZXMpIG1wci5ib3hwbG90KGRmLmNsdXN0ZXIwMikKaWYgKCFlbXB0eV9ub2RlcykgbXByLmJveHBsb3QoZGYuY2x1c3RlcjAzKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuYm94cGxvdChkZi5jbHVzdGVyMDQpCmlmICghZW1wdHlfbm9kZXMpIG1wci5ib3hwbG90KGRmLmNsdXN0ZXIwNSkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmJveHBsb3QoZGYuY2x1c3RlcjA2KQppZiAoIWVtcHR5X25vZGVzKSBtcHIuYm94cGxvdChkZi5jbHVzdGVyMDcpCmlmICghZW1wdHlfbm9kZXMpIG1wci5ib3hwbG90KGRmLmNsdXN0ZXIwOCkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmJveHBsb3QoZGYuY2x1c3RlcjA5KQppZiAoIWVtcHR5X25vZGVzKSBtcHIuYm94cGxvdChkZi5jbHVzdGVyMTApCmBgYAoKIyMjIExvY2FsaXphY2nDs24gZ2VvZ3LDoWZpY2EgZGUgbGFzIGVzdGFjaW9uZXMgZGUgbWVkaWRhIGRlIGNhZGEgY2x1c3RlcgoKYGBge3J9CiMgQWdydXBhIHBvciBsb25naXR1ZCB5IGxhdGl0dWQgcGFyYSByZWxsZW5hciBlbCBtYXBhIGNvbiBtZW5vcyBkYXRvcy4KaWYgKCFlbXB0eV9ub2RlcykgewogIGRmLmNsdXN0ZXIwMS5ncm91cGVkIDwtIG1wci5ncm91cF9ieV9nZW8oZGYuY2x1c3RlcjAxKQogIGRmLmNsdXN0ZXIwMi5ncm91cGVkIDwtIG1wci5ncm91cF9ieV9nZW8oZGYuY2x1c3RlcjAyKQogIGRmLmNsdXN0ZXIwMy5ncm91cGVkIDwtIG1wci5ncm91cF9ieV9nZW8oZGYuY2x1c3RlcjAzKQogIGRmLmNsdXN0ZXIwNC5ncm91cGVkIDwtIG1wci5ncm91cF9ieV9nZW8oZGYuY2x1c3RlcjA0KQogIGRmLmNsdXN0ZXIwNS5ncm91cGVkIDwtIG1wci5ncm91cF9ieV9nZW8oZGYuY2x1c3RlcjA1KQogIGRmLmNsdXN0ZXIwNi5ncm91cGVkIDwtIG1wci5ncm91cF9ieV9nZW8oZGYuY2x1c3RlcjA2KQogIGRmLmNsdXN0ZXIwNy5ncm91cGVkIDwtIG1wci5ncm91cF9ieV9nZW8oZGYuY2x1c3RlcjA3KQogIGRmLmNsdXN0ZXIwOC5ncm91cGVkIDwtIG1wci5ncm91cF9ieV9nZW8oZGYuY2x1c3RlcjA4KQogIGRmLmNsdXN0ZXIwOS5ncm91cGVkIDwtIG1wci5ncm91cF9ieV9nZW8oZGYuY2x1c3RlcjA5KQogIGRmLmNsdXN0ZXIxMC5ncm91cGVkIDwtIG1wci5ncm91cF9ieV9nZW8oZGYuY2x1c3RlcjEwKQp9CmBgYAoKYGBge3J9CmlmICghZW1wdHlfbm9kZXMpIG1wci5kcmF3X21hcChzcGFpbiwgZGYuY2x1c3RlcjAxLmdyb3VwZWQpCmlmICghZW1wdHlfbm9kZXMpIG1wci5kcmF3X21hcChzcGFpbiwgZGYuY2x1c3RlcjAyLmdyb3VwZWQpCmlmICghZW1wdHlfbm9kZXMpIG1wci5kcmF3X21hcChzcGFpbiwgZGYuY2x1c3RlcjAzLmdyb3VwZWQpCmlmICghZW1wdHlfbm9kZXMpIG1wci5kcmF3X21hcChzcGFpbiwgZGYuY2x1c3RlcjA0Lmdyb3VwZWQpCmlmICghZW1wdHlfbm9kZXMpIG1wci5kcmF3X21hcChzcGFpbiwgZGYuY2x1c3RlcjA1Lmdyb3VwZWQpCmlmICghZW1wdHlfbm9kZXMpIG1wci5kcmF3X21hcChzcGFpbiwgZGYuY2x1c3RlcjA2Lmdyb3VwZWQpCmlmICghZW1wdHlfbm9kZXMpIG1wci5kcmF3X21hcChzcGFpbiwgZGYuY2x1c3RlcjA3Lmdyb3VwZWQpCmlmICghZW1wdHlfbm9kZXMpIG1wci5kcmF3X21hcChzcGFpbiwgZGYuY2x1c3RlcjA4Lmdyb3VwZWQpCmlmICghZW1wdHlfbm9kZXMpIG1wci5kcmF3X21hcChzcGFpbiwgZGYuY2x1c3RlcjA5Lmdyb3VwZWQpCmlmICghZW1wdHlfbm9kZXMpIG1wci5kcmF3X21hcChzcGFpbiwgZGYuY2x1c3RlcjEwLmdyb3VwZWQpCmBgYAo=